简体   繁体   English

使用scanf将字符串读入字符串数组

[英]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). 我正在尝试制作一个简单的程序,该程序始终使用scanf从标准输入中读取字符串,并将其放入字符串数组中(现在,我仅使用3个单词对其进行测试,因此最后仅使用3个打印语句)。 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. 我可以继续读取直到没有更多的字符串为止,但是遇到一个错误,在该错误中,循环完成后,数组中的所有字符串都是最后一个读入的字符串。我尝试将print语句放入其中要调试的循环,它正在读取正确的字符串。 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). 您正在为每个w_arr元素重用w (即它们都指向同一位置)。 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 . 确保w_arr所有元素w_arr指向相同的指针w The data being held at w after the end of the while loop is that last input that was read. while循环结束后在w保留的数据是最后读取的输入。 Hence, you see the same output from all the elements of w_arr . 因此,您将从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_arr[c] = strdup(w); 

    If strdup is not available on your platform, it is easy to implement one. 如果您的平台上没有strdup ,则很容易实现。

     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. while循环中为第二,第三等输入分配w内存。

    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. 确保在函数结束之前添加调用以释放mmory。

    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. 您正在将w_arr的每个元素设置为仅分配一次的单个缓冲区w You can see this by printing out the contents of w_arr by adding this line after your loop: 您可以通过在循环后添加以下行来打印出w_arr的内容来查看此内容:

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. 如您所见, w_arr每个元素w_arr指向内存中的相同地址。 To fix this, you will need to allocate w each time and then assign the new character array to w_arr. 要解决此问题,您将需要每次分配w ,然后将新的字符数组分配给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 . w_arr[c]指向w它在循环结束时的内容是最后读取的字符串,因此您将得到最后一个打印的字符串。

You allocate memory to each pointer in w_arr - 您为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 - 然后阅读后使用strcpy

Note - Change your scanf to while (scanf("%9s", w) == 1) { so as to avoid getting more than required characters in w . 注意 -将scanf更改为while (scanf("%9s", w) == 1) {以避免在w获得超出要求的字符数。

You'd better use strdup and include string.h . 您最好使用strdup并包含string.h

w_arr[c] = w;

To: 至:

w_arr[c] = strdup(w);

And strcpy is not safe you'd better use strncpy instead; 而且strcpy是不安全的,您最好改用strncpy

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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