Je me débat avec cela depuis un moment et j'ai pensé que je pourrais aussi bien demander de l'aide au lieu de me cogner la tête plus fort contre un mur.

Alors disons que vous avez la chaîne "10 10 10 4 4 4 9 9 9 2" et vous voulez le parcourir, retirez les nombres un par un et ajoutez-le à un tableau d'entiers à utiliser.

J'ai prototypé BEAUCOUP et je continue à faire plus de travail que nécessaire. Au début, j'utilisais strtok(), mais les gens ont dit que c'était obsolète et que ce serait plus facile à utiliser strsep()

Comment pourrais-je procéder?

Toute aide serait grandement appréciée!

Ma fonction semble toujours renvoyer un tableau int plein de zéros. Pourquoi est-ce?

int *parse_line(char *line){
    char sNumArray[MAX];
    strcpy(sNumArray, line);
    char *tokens = NULL;
    int *numbers = malloc(sizeof(int) * MAX);
    tokens = strtok(sNumArray, " ");
    for(int i = 0; ; i++) {
        numbers[i] = atoi(tokens);
        printf("%d \n", atoi(tokens));
        tokens = strtok(NULL, " ");
        if (tokens == NULL)
            break;
    }
    return numbers;
}

Ce sont mes variables que je définis dans le main et que j'appelle ma fonction avec ...

int *skyline;
skyline = parse_line(line);
for (int j = 0; j < 100 ; ++j) {
    printf("%d \n", skyline[j]);
}
0
Jak 20 nov. 2018 à 04:25

4 réponses

Meilleure réponse

Je pense que cela fera ce que vous voulez.

#include "stdafx.h"

#include <stdio.h>
#include <iostream>
#include <math.h>
#include <stdlib.h>
using namespace std;

#define MAX 100

int *parse_line(char *line, int *numInts) {
    char sNumArray[MAX];
    strcpy(sNumArray, line);
    int *numbers = (int *) malloc(sizeof(int) * MAX);
    char *tokens = strtok(sNumArray, " ");
    for (int i = 0; ; i++) {
        numbers[i] = atoi(tokens);
        tokens = strtok(NULL, " ");
        if (tokens == NULL) {
            *numInts = i+1;
            break;
        }       
    }

    return numbers;
}

int main() {
    char *line = "10 10 10 4 4 4 9 9 9 2";
    int numIntsExtracted = 0;
    int *skyline = parse_line(line, &numIntsExtracted);

    for (int j = 0; j < numIntsExtracted; ++j) {
        printf("%d \n", skyline[j]);
    }
    return 0;
}

Et le résultat que j'obtiens après l'avoir exécuté.

10
10
10
4
4
4
9
9
9
2
0
driftwood 20 nov. 2018 à 23:24

J'aime utiliser la fonction strtol() pour cela, car si vous lui passez un pointeur, il renverra le point suivant pour continuer l'analyse. Il existe également des versions non signées, par exemple: strtoul(). Ils sont standard depuis C99. De plus, strtol() peut analyser l'hexadécimal et gère les erreurs un peu mieux que des fonctions plus anciennes comme atoi() (qui renvoie 0 en cas d'erreur).

La partie importante du code ci-dessous est le résultat de strtol(). Lorsque next_number n'est pas modifié après l'appel, il n'y a plus d'entrée (ou une erreur s'est produite). La variable ptr est utilisée pour garder une trace de l'endroit où l'analyse en est dans la chaîne. Il est donné à strtol(), qui change next_number pour qu'il pointe vers l'élément suivant, alors ptr saute en avant - assigné à next_number (au-delà de l'élément qui vient d'être analysé), et le le processus se répète.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char *number_str = "10 10 10 4 4 4 9 9 9 2";
    char *ptr;
    char *next_number;
    int   numbers[1000];
    int   number_count = 0;
    long  num;

    next_number = number_str;

    do
    {
        ptr = next_number;
        num = strtol(ptr, &next_number, 10);
        if (ptr != next_number) // found one
        {
            numbers[number_count] = (int)num;
            printf("Stored %3d into numbers[%d]\n", numbers[number_count], number_count);
            number_count += 1;
        }
    } while(ptr != next_number);

    return 0;
}
0
Kingsley 20 nov. 2018 à 03:14

Utilisez simplement scanf () pour obtenir chaque numéro un par un dans la boucle for ou while.

for i = 0 to n
scanf(“%d”, &num);

Veuillez consulter Google ou Bing Search en ligne comment cela se fait avec de nombreux exemples disponibles.

-5
anand 20 nov. 2018 à 02:36

Vous avez trois options principales (1) utiliser strtol comme prévu, en utilisant le paramètre *endptr pour faire avancer la position de lecture actuelle dans la chaîne jusqu'à un après le dernier chiffre converti, ou (2) passer à sscanf en utilisant le spécificateur "%n" pour rapporter le nombre de caractères utilisés dans la conversion à int (ou n'importe quel type) et en utilisant cette valeur pour avancer la position de lecture de la même manière; ou (3) tokenizing la chaîne avec strtok puis en utilisant strtol (comme atoi ne doit pas être utilisé car il ne fournit absolument aucune vérification d'erreur). Il n'est vraiment pas nécessaire d'utiliser à la fois strtok et strtol car strtol fournit déjà un moyen d'avancer au-delà des chiffres convertis. Vous dupliquez essentiellement ce qui a déjà été fait par strtol en utilisant un appel à strtok - mais c'est une voie valable.

Par exemple, en utilisant strtol, vous pouvez faire quelque chose comme ceci:

#include <stdio.h>
#include <stdlib.h>     /* for strtol */
#include <string.h>     /* for strncpy */
#include <errno.h>      /* for errno */

#define MAXC 1024   /* constant - max chars in line */

int main (void) {

    char str[MAXC] = "";    /* str to hold line, initialized all zero */

    while (fgets (str, MAXC, stdin)) {  /* read each line of input */
        char *p = str,      /* pointer for strtol */
            *endptr = NULL; /* end pointer for strtol */

        while (*p) {    /* work down str parsing integer or hex values */
            long val = strtol (p, &endptr, 0);  /* convert from p */

            /* validate conversion */
            if (p != endptr) {  /* were digits converted? */
                if (!errno) {   /* if errno 0, successful conversion */
                    char ascii[MAXC] = "";  /* for string converted */

                    strncpy (ascii, p, endptr - p); /* copy to ascii */
                    ascii[endptr-p] = 0;    /* nul-terminate ascii */

                    /* test whether string begins "0x" or "0X", output */
                    if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X'))
                        printf ("hex conversion:  %-10s %10lu  0x%lx\n",
                                ascii, val, val);
                    else
                        printf ("int conversion:  %-10s % ld\n",
                                ascii, val);
                }
                p = endptr; /* advance p to 1-past end of converted string */
            }

            /* find start of next valid number in str, including (+/-) */
            for (; *p; p++) {
                if ('0' <= *p && *p <= '9')  /* positive value */
                    break;          /* explicitly signed value */
                if ((*p == '+' || *p == '-') && '0' <= *(p+1) && *(p+1) <= '9')
                    break;
            }
        }
    }

    return 0;
}

Exemple d'utilisation / de sortie

$ echo "10 10 10 4 4 4 9 9 9 2" | ./bin/fgets_strtol_any
int conversion:  10          10
int conversion:  10          10
int conversion:  10          10
int conversion:  4           4
int conversion:  4           4
int conversion:  4           4
int conversion:  9           9
int conversion:  9           9
int conversion:  9           9
int conversion:  2           2

Ou convertir tous les nombres entiers dans un fichier désordonné, par exemple

Exemple de fichier d'entrée

$ cat dat/10intmess.txt
8572,;a -2213,;--a 6434,;
a- 16330,;a

- The Quick
Brown%3034 Fox
12346Jumps Over
A
4855,;*;Lazy 16985/,;a
Dog.
11250
1495

Exemple d'utilisation / de sortie

$ ./bin/fgets_strtol_any <dat/10intmess.txt
int conversion:  8572        8572
int conversion:  -2213      -2213
int conversion:  6434        6434
int conversion:  16330       16330
int conversion:  3034        3034
int conversion:  12346       12346
int conversion:  4855        4855
int conversion:  16985       16985
int conversion:  11250       11250
int conversion:  1495        1495

Utilisation de sscanf

De même, vous pouvez utiliser sscanf, mais sachez qu'il ne fournit pas le niveau ou le degré de gestion des erreurs - ce qui signifie que vous pouvez seulement savoir qu'il a réussi à convertir le texte ou qu'il a échoué. Non entre les deux, pas de signalement de dépassement de capacité ou de sous-dépassement via errno. Mais encore, avec strtok sont d'autres moyens valides d'analyser les entiers d'une ligne de texte, par exemple

#include <stdio.h>
#include <stdlib.h>

#define MAXC 1024

int main (int argc, char **argv) {

    char buf[MAXC] = "";    /* buffer to hold MAXC chars at a time */
    int nval = 0;           /* total number of integers found */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    while (fgets (buf, MAXC, fp)) {

        char *p = buf;      /* pointer to line */
        int val,            /* int val parsed */
            nchars = 0;     /* number of chars read */

        /* while chars remain in buf and a valid conversion to int takes place
        * output the integer found and update p to point to the start of the
        * next digit.
        */
        while (*p) {
            if (sscanf (p, "%d%n", &val, &nchars) == 1) {
                printf (" %d", val);
                if (++nval % 10 == 0)     /* output 10 int per line */
                    putchar ('\n');
            }
            p += nchars;        /* move p nchars forward in buf */

            /* find next number in buf */
            for (; *p; p++) {
                if (*p >= '0' && *p <= '9') /* positive value */
                    break;
                if (*p == '-' && *(p+1) >= '0' && *(p+1) <= '9') /* negative */
                    break;
            }
        }
    }
    printf ("\n %d integers found.\n", nval);

    if (fp != stdin) fclose (fp);     /* close file if not stdin */

    return 0;
}

Exemple d'utilisation / de sortie

$ echo "10 10 10 4 4 4 9 9 9 2" | ./bin/fgets_sscanf_int_any_ex
 10 10 10 4 4 4 9 9 9 2

 10 integers found.

Ou avec une entrée désordonnée

$ echo "1, 2 buckle my shoe, 3, 4..." | ./bin/fgets_sscanf_int_any_ex
 1 2 3 4
 4 integers found.

Utiliser strtok serait simplement un "front-end" à la conversion avec strtol montré dans le premier exemple (qui fournit sa propre façon de tokeniser les valeurs numériques). Vous faites simplement une boucle sur votre tampon en appelant strtok avec les délimiteurs de " \n" (espace nouvelle ligne) puis en utilisant strtol pour convertir la chaîne pointée. (ici vous utilisez simplement endptr pour valider que les chiffres ont été convertis et en ignorant son utilisation pour avancer au-delà des chiffres convertis. Essentiellement, strtok duplique ce qui est déjà fait par strtok, mais si cela fait c'est plus facile à comprendre, et vous pouvez vivre avec l'appel en double, c'est très bien. Vous pouvez faire quelque chose comme ce qui suit.

    while (fgets (buf, MAXC, fp)) {
        char *p = buf;  /* pointer to buf to use with strtok */
        /* 1st call using buffer, all remaining calls using NULL */
        for (p = strtok (p, " \n"); p; p = strtok (NULL, " \n")) {
            errno = 0;                          /* reset errno */
            char *endptr;                       /* end pointer */
            long tmp = strtol (p, &endptr, 0);  /* convert using long */
            if (p != endptr) {      /* validate digits converted */
                /* now validate value within range of int */
                if (!errno && INT_MIN <= tmp && tmp <= INT_MAX)
                    /* you have an integer! */
            }
            else if (tmp == 0)
                /* no digits were converted */
        }
    }

Examinez les choses et dites-moi si vous avez d'autres questions.

3
David C. Rankin 20 nov. 2018 à 03:48