使用strncpy时堆栈和堆的奇怪行为

时间:2012-06-11 20:49:03

标签: c string stack heap

我发现了一个非常有趣的问题。

当我使用以下代码时:

int main() {
    char * in = "hi, ";
    char str[10];
    strncpy(str, in, 2);
    printf("output = %s", str);
    return 0;
}

我的结果是什么,printf没有用。

但如果我使用它:

int main() {
    char * in = "hi, ";
    char * str = malloc(sizeof(char) * 10) ;
    strncpy(str, in, 2);
    printf("output = %s", str);
    return 0;
}

我可以得到我期望的结果。

为什么会这样?是因为堆栈和堆?究竟是如何产生这种巨大差异的?

3 个答案:

答案 0 :(得分:6)

问题 - 在两个情况下 - 是在您致电strncpy后,您的字符串无法正常终止。

您指定复制2个字符,而源字符串in的长度为4.因此strncpy将复制2个字符,因为小于源字符串的长度不会添加空终结符 - 要理解为什么会这样,请查看docs for strncpy

If count is reached before the entire string src was copied, the resulting character array is not null-terminated.

在这种情况下,您需要:

str[2] = '\0';

在'strncpy'之后。

第二种情况可能似乎有效,因为您从malloc获得的缓冲区恰好初始化为全零,但不应依赖对此。

请查看docs for strncpy,注意空终止的例外情况,一般情况下,请注意字符串终止!

有关更多详细信息,请参阅:Why are strings in C++ usually terminated with '\0'?

答案 1 :(得分:5)

代码编译得很好。运行时错误可能是因为您没有使用null终止str

从手册页:

  

strncpy()函数类似,除了最多n个字节   src被复制。警告:如果前n个中没有空字节   src的字节,放在dest中的字符串          不能为空终止。

str[2]=0;之后添加strncpy()

答案 2 :(得分:1)

您可以使用零来初始化内存,使其处于“安全”状态。

查看以下代码,

int main() {
    char * in = "hi, ";
    char str[10]={0};    
    strncpy(str, in, 2);
    printf("output = %s", str);
    return 0;
}

int main() {
    char * in = "hi, ";
    char * str = calloc(10,sizeof(char));
    strncpy(str, in, 2);
    printf("output = %s", str);
    free(str);      //<<Important step
    return 0;
}

str[2] = '\0';也是一种有效的解决方案。