2016-03-18 149 views
0

我试图做一个简单的程序,使用scanf将标准输入中的字符串读入并放入字符串数组中(现在我只是使用它进行测试3个单词,因此最后只有3个打印语句)。我能够继续阅读,直到没有更多的字符串,但是我遇到了一个错误,在循环完成后,数组中的所有字符串都是最后一个读入的字符串。我试着把一个print语句放在循环进行调试,并且正在读取正确的字符串。但是,当循环结束时,数组中的所有字符串都是最后一个读入的字符串。有谁能指出我在哪里出错吗?谢谢。使用scanf将字符串读取到字符串数组中

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

您需要'malloc'一个新的'w'缓冲每'scanf'(或得到一个新的缓冲液如某种其他方式'w_arr并[c] =的strdup(W)')。就像这样,所有数组条目都指向同一个缓冲区,其内容被每个scanf所覆盖。 – kaylum

+0

啊。对不起,我是新来的c。所以基本上,我所有的数组中的条目都不是指向一个字符串,而是指向一个指针。所以当循环完成时,它们都指向相同的指针,这是最后一个字符串的地址? – PCR

+0

@PCR它不是“字符串的地址” - 它是内存中某个空间的地址。然后你读入该空间的第一个字符串,并使'w_arr [0]指向该空间。然后你读第二个字符串进入该空间,并让'w_arr [1]'指向那个空间。然后你读入第三个字符串,并使'w_arr [2]'指向那个空间。最终结果是'w_arr [0]','w_arr [1]'和'w_arr [2]'都指向该空间,并且该空间包含第三个字符串(因为您覆盖了前两个字符)。 – immibis

回答

1

您正在为每个w_arr元素重复使用w(即它们都指向相同的位置)。您需要分配为每个字符串

变化:

w_arr[c] = w; 

要:

w_arr[c] = strdup(w); 
+0

1)strdup()不是标准C. 2)如果OP在Linux上会发生什么? – Michi

+0

@Michi strdup符合POSIX 1003.1标准。自1980年以来,POSIX [来自IEEE]和ISO已经并行运行。大约20年前,ISO失去了对“libc规范”的控制。大多数libc坚持POSIX而不是ISO。至于linux,strdup工作正常 –

0
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 -

注意 - 改变你的scanfwhile (scanf("%9s", w) == 1) {以免高于所需的字符越来越w

1

声明

w_arr[c] = w; 

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

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

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

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

确保添加通话功能月底前解除分配mmory。

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

“分配给w_arr [c]时使用strdup”如果OP在Linux上,strdup()将无济于事。 – Michi

0

你最好使用strdup和包括string.h

w_arr[c] = w; 

要:

w_arr[c] = strdup(w); 

而且strcpy是不是安全,你最好使用strncpy代替;

+0

strdup()不是标准C. OP没有提到他是否在windows上。如果他在Linux上,这个答案不会帮助他解决问题。 – Michi

1

您正在将w_arr的每个元素设置为仅分配一次的单个缓冲区w

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

您会看到类似以下的输出:你可以通过你的循环后,加入这一行看到打印出的w_arr内容

[[email protected] 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; 
} 
相关问题