从strncpy()函数获取奇怪的字符

时间:2016-04-08 17:50:49

标签: c arrays string c-strings

我应该从文件中加载一个名称列表,然后在第二个文件中找到这些名称并将它们加载到一个带有其他数据的结构中(为简单起见,我将它们加载到另一个名为“< EM>测试”。

第一部分很好,我打开一个文件并将所有名称加载到名为 namesArr 的二维数组中。 第二部分是意外字符出现的地方,我无法理解原因。这是函数的代码:

void loadStructure(void){
    char line[MAX_PL_LENGTH], *found;
    int i, j=0;
    char test[20][20];

    FILE *plotPtr=fopen(PLOT_FILE_PATH, "r");
    if (plotPtr==NULL){perror("Error 05:\nError opening a file in loadStructure function. Check the file path"); exit(-5);}
    while(fgets(line, MAX_PL_LENGTH, plotPtr)!=NULL){                   // This will load each line from a file to an array "line" until it reaches the end of file.
        for(i=0; i<numOfNames; i++){                                    // Looping through the "namesArr" array, which contains the list of 20 character names.
            if((found=strstr(line, namesArr[i]))!=NULL){                // I use strstr() to find if any of those names appear in the particular line.
                printf("** %s", found);                                 // Used of debugging.
                strncpy(test[j], found, strlen(namesArr[i])); j++;      // Copying the newly found name to test[j] (copying only the name, by defining it's length, which is calculated by strlen function).
            }
        }
    }
    fclose(plotPtr);
    printf("%s\n", test[0]);
    printf("%s\n", test[1]);
    printf("%s\n", test[2]);
}

这是我得到的输出:

...20 names were loaded from the "../Les-Mis-Names-20.txt".
** Leblanc, casting
** Fabantou seems to me to be better," went on M. Leblanc, casting
** Jondrette woman, as she stood
Leblanct╕&q
Fabantou
Jondretteⁿ  └

Process returned 0 (0x0)   execution time : 0.005 s
Press any key to continue.

问题是,为什么我在新创建的数组中会出现“╕&amp; q”和“ⁿ└”这样的字符?而且,还有其他更有效的方法来实现我想要做的事情吗?

4 个答案:

答案 0 :(得分:2)

问题是如果指定的长度小于源字符串,strncpy不会在目标数组中存储空值(这里总是如此)。因此,test数组中的所有垃圾都将保留在那里。

您可以通过将test数组归零来修复此特定问题,无论是在声明它时:

char test[20][20] = { { 0 } };

或当你使用它时:

memset(test[j], 0, 20);
strncpy(test[j], found, strlen(namesArr[i]));

但一般而言,出于这个原因,最好避免使用strncpy

答案 1 :(得分:2)

strncpy的长度限制应该基于目标大小,而不是源长度:这是strcpy使用它的点,它仅使用源长度。在你的代码中

strncpy(test[j], found, strlen(namesArr[i]));

length参数来自源数组,这违背了使用strncpy的目的。此外,如果函数复制完整的字节数限制,则nul终结符将不存在,因此代码应为

strncpy(test[j], found, 19);        // limit to target size, leaving room for terminator
test[j][19] = '\0';                 // add terminator (if copy did not complete)

是否正确加载namesArr[]文件是另一个潜在问题,因为您没有显示代码。

答案 2 :(得分:2)

编辑:

对上一个答案稍作修改:

1)由于您正在使用C字符串,因此请确保(因为strncpy(...)不会为您执行此操作)null您终止缓冲区。
2)当使用strncpy时,length参数应表示目标字符串字节容量 - 1(空终止符的空格),而不是源字符串长度。

...
int len = strlen(found)
memset(test[j], 0, 20);
strncpy(test[j], found, 19);//maximum length (19) matches array size 
                            //of target string -1 ( test[j] ).
if(len > 19) len = 19; //in case length of found is longer than the target string.
test[j][len+1] = 0;
...

答案 3 :(得分:0)

除了Chris Dodd所说的,引自man strncpy

  

strncpy()函数与[strong> strcpy()函数类似,不同之处在于复制了src的最多 n 个字节。 警告:如果src的前n个字节中没有空字节,则放在dest中的字符串将不会以空值终止。

由于strncpy调用中的size参数是字符串的长度,因此包含字符串末尾的空字节,因此您的目标字符串将不会从此调用中以null结尾。