简体   繁体   中英

Using scanf to read strings into an array of strings

I'm trying to make a simple program that keeps reading strings from the standard input using scanf and putting them into an array of strings (Right now I'm just testing it using 3 words, hence only 3 print statements at the end). I'm able to keep reading until there are no more strings, however I've encountered a bug where after the looping is done, all the strings in the array are the last string read in. I've tried putting a print statement within the loop to debug, and it is reading in the correct string. However when the looping is finished, all the strings in the array are the last string read in. Can anyone point out where I'm going wrong here? Thanks.

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



int main(void) {
    int c = 0;
    char** w_arr = malloc(3*sizeof(char*));
    char* w = malloc(10*sizeof(char));

    while (scanf("%s", w) == 1) {
        w_arr[c] = w;
        //printf("%s", w_arr[c]); debug print statement
        c++;
    }

    printf("%s, %s, %s\n", w_arr[0], w_arr[1], w_arr[2]);
    return 0;
}

You are reusing w for each w_arr element (ie they all point to the same place). You need to allocate one for each string

Change:

w_arr[c] = w;

To:

w_arr[c] = strdup(w);

The statement

    w_arr[c] = w;

makes sure that all the elements of w_arr point to the same pointer, w . The data being held at w after the end of the while loop is that last input that was read. Hence, you see the same output from all the elements of w_arr .

I can think of couple of ways to solve this problem.

  1. Use strdup when assigning to w_arr[c]

     w_arr[c] = strdup(w); 

    If strdup is not available on your platform, it is easy to implement one.

     char* strdup(char const* in) { char* ret = malloc(strlen(in)+1); strcpy(ret, in); return ret; } 
  2. Allocate memory for w in the while loop for second, third, etc. inputs.

    Instead of

     char* w = malloc(10*sizeof(char)); while (scanf("%s", w) == 1) { w_arr[c] = w; //printf("%s", w_arr[c]); debug print statement c++; } 

    use

     char* w = malloc(10*sizeof(char)); while (scanf("%s", w) == 1) { w_arr[c] = w; //printf("%s", w_arr[c]); debug print statement c++; w = malloc(10*sizeof(char)); } 

Make sure to add calls to deallocate mmory before the end of the function.

    free(w);
    for (int i = 0; i < 3; ++i )
       free(w_arr[i]);

You are setting every element of w_arr to the single buffer w that was only allocated for once. You can see this by printing out the contents of w_arr by adding this line after your loop:

printf("Addresses of strings: %p, %p, %p\n", w_arr[0], w_arr[1], w_arr[2]);

You should see output similar to the following:

[hwibell@localhost tmp]$ ./strings
123
456
789
Addresses of strings: 0x1b0b030, 0x1b0b030, 0x1b0b030 <-- Same address!
Contents of strings: 789, 789, 789

As you can see, each element of w_arr points to the same address in memory. To fix this, you will need to allocate w each time and then assign the new character array to w_arr.

#define NUM_OF_STRINGS 3
#define MAX_CHARS      10

int main(void) {
    char** w_arr = malloc(NUM_OF_STRINGS * sizeof(char*));

    for (int i = 0; i < NUM_OF_STRINGS; ++i) {
        w_arr[i] = malloc(MAX_CHARS * sizeof(char)); // allocate a new buffer for each element in w_arr
        scanf("%s", w_arr[i]);
    }

    printf("%s, %s, %s\n", w_arr[0], w_arr[1], w_arr[2]);
    return 0;
}
 w_arr[c] = w;

As w_arr[c] points to w whose content at end of loop is the last read string ,so you get the last string printed .

You allocate memory to each pointer in w_arr -

 char** w_arr = malloc(3*sizeof(char*));      //allocated memory for 3 char *

 while (scanf("%s", w) == 1 && c<3) {
      w_arr[c]=malloc(10*sizeof(**w_arr));    // allocate memory to each char *
      strcpy(w_arr,w);                        //copy string
    //printf("%s", w_arr[c]); debug print statement
      c++;
 }

and then use strcpy after reading -

Note - Change your scanf to while (scanf("%9s", w) == 1) { so as to avoid getting more than required characters in w .

You'd better use strdup and include string.h .

w_arr[c] = w;

To:

w_arr[c] = strdup(w);

And strcpy is not safe you'd better use strncpy instead;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM