【问题标题】:Using scanf to read strings into an array of strings使用 scanf 将字符串读入字符串数组
【发布时间】:2016-03-18 03:23:33
【问题描述】:

我正在尝试制作一个简单的程序,该程序使用 scanf 从标准输入中读取字符串并将它们放入字符串数组中(现在我只是使用 3 个单词对其进行测试,因此只有 3 个打印语句结尾)。我可以继续阅读,直到没有更多的字符串,但是我遇到了一个错误,在循环完成后,数组中的所有字符串都是最后一个读入的字符串。我尝试在其中放置一个 print 语句要调试的循环,它正在读取正确的字符串。但是,当循环完成时,数组中的所有字符串都是最后一个读入的字符串。谁能指出我在这里出错的地方?谢谢。

#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;
}

【问题讨论】:

  • 您需要为每个scanf 提供malloc 一个新的w 缓冲区(或其他获取新缓冲区的方法,例如w_arr[c]=strdup(w))。事实上,所有数组条目都指向同一个缓冲区,每个 scanf 都会覆盖其内容。
  • 啊。对不起,我是 c 的新手。所以基本上我在数组中的所有条目实际上都不是指向一个字符串,而是指向一个指针。那么当循环完成时,它们都指向同一个指针,也就是最后一个字符串的地址?
  • @PCR 这不是真正的“字符串地址”——它是内存中某个空间的地址。然后将第一个字符串读入该空间,并使w_arr[0] 指向该空间。然后将第二个字符串读入该空间,并使w_arr[1] 指向该空间。然后将第三个字符串读入该空间,并使w_arr[2] 指向该空间。最终结果是w_arr[0]w_arr[1]w_arr[2] 都指向那个空间,并且那个空间包含第三个字符串(因为你覆盖了前两个)。

标签: c


【解决方案1】:

您正在为每个 w_arr 元素重用 w(即它们都指向同一个地方)。您需要为每个字符串分配一个

变化:

w_arr[c] = w;

收件人:

w_arr[c] = strdup(w);

【讨论】:

  • 1) strdup() 不是标准 C。2) 如果 OP 在 Linux 上会发生什么?
  • @Michi strdup 符合 POSIX 1003.1。自 1980 年代以来,POSIX [来自 IEEE] 和 ISO 一直并行运行。大约 20 年前,ISO 失去了对“libc 规范”的控制。大多数 libc 都遵循 POSIX 而不是 ISO。至于 linux,strdup 工作正常
【解决方案2】:

您正在将 w_arr 的每个元素设置为仅分配一次的单个缓冲区 w。您可以通过在循环后添加这一行来打印出w_arr 的内容来看到这一点:

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

您应该会看到类似于以下内容的输出:

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

如您所见,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;
}

【讨论】:

    【解决方案3】:

    声明

        w_arr[c] = w;
    

    确保w_arr 的所有元素都指向同一个指针w。在while 循环结束后保存在w 的数据是最后读取的输入。因此,您会从 w_arr 的所有元素中看到相同的输出。

    我可以想出几种方法来解决这个问题。

    1. 分配给w_arr[c]时使用strdup

      w_arr[c] = strdup(w);
      

      如果strdup 在您的平台上不可用,则很容易实现。

      char* strdup(char const* in)
      {
          char* ret = malloc(strlen(in)+1);
          strcpy(ret, in);
          return ret;
      }
      
    2. while 循环中为第二个、第三个等输入的w 分配内存。

      代替

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

      使用

      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));
      }
      

    确保在函数结束前添加调用以释放内存。

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

    【讨论】:

    • "在分配给 w_arr[c] 时使用 strdup" 如果 OP 在 Linux 上 strdup() 将无济于事。
    【解决方案4】:

    您最好使用strdup 并包含string.h

    w_arr[c] = w;
    

    收件人:

    w_arr[c] = strdup(w);
    

    strcpy 不安全,你最好改用strncpy

    【讨论】:

    • strdup() 不是标准C。OP没有提到他是否在Windows上。如果他在 Linux 上,这个答案对他的问题没有帮助。
    【解决方案5】:
     w_arr[c] = w;
    

    由于w_arr[c] 指向w,其循环末尾的内容是最后读取的字符串,因此您将打印最后一个字符串。

    你为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++;
     }
    

    然后阅读后使用strcpy -

    注意 - 将您的 scanf 更改为 while (scanf("%9s", w) == 1) { 以避免在 w 中获得超过所需的字符。

    【讨论】:

      猜你喜欢
      • 2019-07-02
      • 2012-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多