输出根据函数调用在程序中的位置而变化

Output changes depending on the position of the function call in the program

我目前正在学习 C。为了变得更好,我想做的一件事是模仿 header 中的 "strcat" 函数。为了制作更精确的副本,我将自己函数的输出与原始函数的输出进行了比较。它们使用相同但不同的 char 数组。但是,如果在原始函数之后调用,我自己的函数的输出会发生变化。这是两个代码变体:

在第一个中,原始的输出是 "1234567890123456",正如预期的那样,我自己的输出是 "123456789123456".经过几十次各种检查后,我发现:“0”字符一旦作为参数传递给函数,就会从 src[0] 中消失:

int main()
{

    char dest[10] = "123456789";
    char src[70] = "0123456";
    printf ("Concatenate |%s| and |%s|\n", dest, src); 


    char dest1[10] = "123456789";
    char src1[70] = "0123456";
    printf ("Normal people do: %s\n", strcat(dest1, src1));    
    printf ("Your filthy code: %s\n",  ft_strcat(dest, src));


    return 0;
}

但是,如果我像这样简单地重新定位函数的 printf:

int main()
{

    char dest[10] = "123456789";
    char src[70] = "0123456";
    printf ("Concatenate |%s| and |%s|\n", dest, src);     
    printf ("Your filthy code: %s\n",  ft_strcat(dest, src));


    char dest1[10] = "123456789";
    char src1[70] = "0123456";
    printf ("Normal people do: %s\n", strcat(dest1, src1));    
    return 0;
}

两个函数都将 return "1234567890123456" 作为输出。

问题是:这怎么可能?我很好奇,因为这些函数处理两组不同的数组,因此不应相互影响。出于某种原因,我的函数的行为取决于它在 int main().

的 body 中的调用时间。

请注意,我特意将 dest[] 数组设置为 10 个字符大,因为我想在意外情况下模仿原始 "strcat" 的行为出色地。尽管这可能是问题的核心,如果我更改它,代码在上述两种情况下都可以正常工作。正如我所说,我感兴趣的是问题的本质,而不是解决问题的方法。

我不确定我的函数的文本是否与此问题相关,但以防万一:

char *ft_strcat(char *dest, char *src)
{
    int dest_end;
    int src_count;

    dest_end = 0;
    src_count = 0;
    while (dest[dest_end])
        dest_end++;
    while (src[src_count])
    {
        dest[dest_end] = src[src_count];        
        src_count++;
        dest_end++;
    }
    dest[dest_end + 1] = '[=12=]';
    return dest;
}

感谢您的任何回答。

这是由于内存重叠.... 因为您要声明 dest1[10]dest[10] 的大小 而不是像这样声明这两个具有更大长度的数组

char dest1[100];
char dest[100];

你的问题就迎刃而解了。

char dest[10] = "123456789";
char src[70] = "0123456";
printf ("Your filthy code: %s\n",  ft_strcat(dest, src));

char dest1[10] = "123456789";
char src1[70] = "0123456";
printf ("Normal people do: %s\n", strcat(dest1, src1)); 

在这两种情况下,使用您自己的函数 ft_strcat(dest, src))strcat(),您调用 undefined behavior 因为目的地指向的 char 数组不可用保存初始化的字符串加上源指向的附加字符串。超出数组范围写入时,程序的行为未定义。


解决方案:

数组destdest1总共需要至少18个元素,10用于容纳"0123456789"7对于终止空字符的附加 "0123456" + 1 元素 [=27=]:

char dest[18] = "123456789";
char dest1[18] = "123456789";

char src[70] = "0123456";
char src1[70] = "0123456";

printf ("Your filthy code: %s\n",  ft_strcat(dest, src));
printf ("Normal people do: %s\n", strcat(dest1, src1));

旁注:

  1. 数组scr1是多余的,因为它只是用来提供追加的字符串,并且它的内容正好等于src中的字符串。您也可以将 src 用于第二个附加过程:
printf ("Normal people do: %s\n", strcat(dest1, src));
  1. srcsrc1 包含每个 70 元素,这是不必要的。他们都只需要有 8 个元素,而不是 70:
src[8] = "0123456";
src1[8] = "0123456";

一个更方便的方法是省略元素的数量,让编译器自动检测所需的元素数量,这样也可以保证你在计数时不会忘记空字符:

src[] = "0123456";
src1[] = "0123456";
  1. 因为指针 src 及其指向的对象都不应在 ft_strcat() 内部进行修改,声明 srcchar const * const src

dest 也可以设为 const,但不要将其设为指向 const 字符的指针:char * const dest.

关于指针 dest.

,您还可以调整 ft_strcat() 的 return 类型

结果是:

char * const ft_strcat(char * const dest, char const * const src)