web-dev-qa-db-fra.com

Comment entrer des chaînes dans un tableau en C?

J'ai essayé d'obtenir les entrées (chaînes) de l'utilisateur et de les stocker dans un tableau.Mais après avoir exécuté ce code, le programme s'est immédiatement écrasé.

#include <stdio.h>
int main() {
    int i;
    char *Word[3];
    for(i=0;i<3;i++)
    {
        printf(" Enter a Word: ");
        scanf("%s", &Word[i]);
    }
    printf("%s ", Word[0]);
    return 0;
}
3
Top Serious

Il semble y avoir un peu de confusion dans ce domaine. Votre principal problème est que vous essayez d'écrire chaque mot à l'adresse de de chacun des pointeurs que vous déclarez avec char *Word[3];. (pour ne pas mentionner que vous n'avez pas de mémoire allouée à l'emplacement indiqué par chaque pointeur - mais vous n'y arrivez jamais car vous essayez d'écrire à l'adresse de chaque pointeur avec plutôt &Word[i] que le pointeur lui-même)

Bien que vous puissiez utiliser scanf, vous rencontrerez rapidement l’un des nombreux écueils liés à la saisie de l’utilisateur avec scanf qui gênera tous les nouveaux programmeurs C (par exemple ne pouvant pas gérer le '\n' laissé dans le tampon d’entrée , ne parvient pas à gérer les espaces dans les chaînes , ne limite pas le nombre de caractères lus/écrits , échec de la validation de la lecture ou du traitement de EOF , etc ... )

Une meilleure approche consiste simplement à utiliser fgets et à couper le '\n' que fgets lit et inclut dans le tampon dans lequel il stocke la chaîne. Un exemple simple serait:

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

#define NWDS 3    /* declare a constant for the maximum number of words */

int main (void) {

    int i, n = 0;
    char Word[NWDS][50] = { "" };       /* provide storage or allocate */

    for (i = 0; i < NWDS; i++) {        /* for a max of NWDS */
        printf ("Enter Word : ");       /* Prompt */
        if (!fgets (Word[i], sizeof Word[i], stdin))  /* read/validate */
            break;                      /* protect against EOF */
        size_t len = strlen (Word[i]);  /* get length */
        if (Word[i][len-1] == '\n')     /* check for trailing '\n' */
            Word[i][--len] = 0;         /* overwrite with nulbyte  */
    }
    n = i;                              /* store number of words read */
    putchar ('\n');                     /* make it pretty */

    for (i = 0; i < n; i++)             /* output each Word read */
        printf (" Word[%d] : %s\n", i, Word[i]);

#if (defined _WIN32 || defined _WIN64)
    getchar();  /* keep terminal open until keypress if on windows */
#endif

    return 0;
}

Allez-y et annulez la saisie à tout moment en générant un EOF lors de la saisie (ctrl + d sur Linux ou ctrl + z sur windoze), vous êtes couvert.

Exemple d'utilisation/sortie

$ ./bin/wordsread
Enter Word : first Word
Enter Word : next Word
Enter Word : last Word

 Word[0] : first Word
 Word[1] : next Word
 Word[2] : last Word

Examine les choses, examine les autres réponses et fais-moi savoir si tu as d'autres questions.

2
David C. Rankin

Dans cette ligne:

scanf("%s", &Word[i]);

Vous devez vous assurer que Word[i] pointe quelque part et a suffisamment d’espace pour occuper la chaîne entrée. Puisque Word[i] est un pointeur char *, vous devez allouer de la mémoire pour cela à un moment donné. Sinon, il s’agit simplement d’un pointeur suspendu ne pointant nulle part.

Si vous souhaitez vous en tenir à scanf(), vous pouvez au préalable allouer de l'espace avec malloc .

malloc() alloue la mémoire demandée sur le tas, puis retourne un pointeur void* à la fin. 

Vous pouvez appliquer malloc() dans votre code comme ceci:

size_t malloc_size = 100;

for (i = 0; i < 3; i++) {
    Word[i] = malloc(malloc_size * sizeof(char)); /* allocates 100 bytes */
    printf("Enter Word: ");
    scanf("%99s", Word[i]); /* Use %99s to avoid overflow */
                            /* No need to include & address, since Word[i] is already a char* pointer */
} 

Remarque: Doit vérifier la valeur renvoyée de malloc(), car il peut renvoyer NULL en cas d'échec. 

De plus, chaque fois que vous allouez de la mémoire avec l'utilisation de malloc(), vous devez utiliser free pour libérer la mémoire demandée à la fin:

free(Word[i]);
Word[i] = NULL; /* safe to make sure pointer is no longer pointing anywhere */

Une autre approche sans scanf

Une manière plus appropriée de lire les chaînes devrait être avec fgets .

char *fgets(char *str, int n, FILE *stream) lit une ligne à partir d'un flux d'entrée et copie les octets dans char *str, auquel doit être attribué une taille de n octets comme seuil d'espace qu'il peut occuper. 

Ce qu'il faut noter à propos de fgets:

  • Ajoute le caractère \n à la fin du tampon. Peut être enlevé facilement.
  • En cas d'erreur, retourne NULL. Si aucun caractère n'est lu, retourne quand même NULL à la fin.
  • Le tampon doit être déclaré de manière statique avec une taille donnée n.
  • Lit le flux spécifié. Soit de stdin ou FILE *

Voici un exemple d'utilisation de cette option pour lire une ligne d'entrée de stdin:

char buffer[100]; /* statically declared buffer */

printf("Enter a string: ");
fgets(buffer, 100, stdin); /* read line of input into buffer. Needs error checking */

Exemple de code avec des commentaires:

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

#define NUMSTR 3
#define BUFFSIZE 100

int main(void) {
    char *words[NUMSTR];
    char buffer[BUFFSIZE];
    size_t i, count = 0, slen; /* can replace size_t with int if you prefer */

    /* loops only for three input strings */
    for (i = 0; i < NUMSTR; i++) {

        /* read input of one string, with error checking */
        printf("Enter a Word: ");
        if (fgets(buffer, BUFFSIZE, stdin) == NULL) {
            fprintf(stderr, "Error reading string into buffer.\n");
            exit(EXIT_FAILURE);
        }

        /* removing newline from buffer, along with checking for overflow from buffer */
        slen = strlen(buffer);
        if (slen > 0) {
            if (buffer[slen-1] == '\n') {
                buffer[slen-1] = '\0';
            } else {
                printf("Exceeded buffer length of %d.\n", BUFFSIZE);
                exit(EXIT_FAILURE);
            }
        } 

        /* checking if nothing was entered */
        if (!*buffer) {
            printf("No string entered.\n");
            exit(EXIT_FAILURE);
        }

        /* allocate space for `words[i]` and null terminator */
        words[count] = malloc(strlen(buffer)+1);

        /* checking return of malloc, very good to do this */
        if (!words[count]) {
            printf("Cannot allocate memory for string.\n");
            exit(EXIT_FAILURE);
        }

        /* if everything is fine, copy over into your array of pointers */
        strcpy(words[count], buffer);

        /* increment count, ready for next space in array */
        count++;
    }  

    /* reading input is finished, now time to print and free the strings */
    printf("\nYour strings:\n");
    for (i = 0; i < count; i++) {
        printf("words[%zu] = %s\n", i, words[i]);
        free(words[i]);
        words[i] = NULL;
    }

    return 0;
}

Exemple d'entrée:

Enter a Word: Hello
Enter a Word: World
Enter a Word: Woohoo

Sortie:

Your strings:
words[0] = Hello
words[1] = World
words[2] = Woohoo
2
RoadRunner

Vous déclarez Word en tant que tableau de pointeur (char * Word [3];). Vous devez allouer de la mémoire pour stocker des données. Allouez la mémoire avec malloc ou des fonctions similaires avant d'attribuer des valeurs.

0
Nithin P
char *Word[3]; // <-- this is an array of 3 dangling pointers, of type char*
// they still point nowhere, we later need to set them to some allocated location.
 ...
 for(i=0;i<3;i++) {
     Word[i] = malloc(some_max_size * sizeof(char)); // <-- allocate space for your Word
     printf(" Enter a Word: ");
     scanf("%s", Word[i]); // <-- not &Word[i]; Word[i] is already a char* pointer
 }
0
A.S.H

Oui, le code se bloque parce que déclarer un tableau de pointeurs de caractères Ne suffit pas, vous devez configurer les pointeurs pour qu'ils pointent Vers la mémoire où les chaînes peuvent être stockées.

Par exemple.

const int maxLen = 32;
char* Word[3] = {NULL,NULL,NULL};

Word[i] = malloc(maxLen);

lisez ensuite la chaîne sur le clavier pour vous assurer qu'elle n'est pas trop long use fgets et maxLen:

printf("Enter a Word:");
fgets(Word[i],maxLen,stdin);
0
Anders