【问题标题】:Output changes depending on the position of the function call in the program输出根据程序中函数调用的位置而变化
【发布时间】:2020-05-01 07:11:04
【问题描述】:

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

在第一个中,原来的输出是“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;
}

这两个函数都会返回 "1234567890123456" 作为输出。

问题是:这怎么可能?我很好奇,因为这些函数针对两组不同的数组,因此不应该相互影响。由于某种原因,我的函数的行为取决于它在 int main() 的主体中被调用的时间。

请注意,我有意将 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] = '\0';
    return dest;
}

感谢您的任何回答。

【问题讨论】:

  • 欢迎来到 SO!如果您检查man page: ... dest 字符串必须有足够的空间用于结果。如果 dest 不够大,程序的行为是不可预测的;缓冲区溢出是攻击安全程序的常用途径。.
  • @ggorlen 谢谢你的回答。我知道这样的代码可以并且将会导致溢出和不可预测的行为,但这是否意味着我无法在这种情况下以任何方式重现原始函数的行为?即使在溢出和其他意外情况等情况下,我也打算模仿“strcat”函数,因此我故意使 dest[] 数组比需要的小。谢谢你的欢迎词,很暖心。
  • unpredictable behaviour 是的,这意味着它是不可预测的。它被称为the behavior of the program is undefined,是的,您不能指望具有未定义行为的程序以任何方式运行。因为它没有定义会发生什么。所以任何事情都有可能发生。
  • how is this possible? - 要回答此类问题,请检查程序的汇编代码。 because these functions address two different sets of arrays - 您的编译器可以将它们优化为一个数组。
  • @KamilCuk 我非常感谢您的帮助。谢谢!

标签: c string strcat string.h


【解决方案1】:
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元素用于终止空字符\0:

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() 内被修改,因此将src 声明为char const * const src

dest 也可以设为 const,但不能将其设为指向 const 的指针 char: char * const dest

您还可以针对指针dest 调整ft_strcat() 的返回类型。

结果是:

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

【讨论】:

  • @EmilNadimanov 我看到你暂时接受了我的回答,但随后拒绝了投票。我更正了有关放置 const 限定符的代码。如果您对此有任何疑问或想了解更多信息,请告诉我。
【解决方案2】:

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

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

您的问题将得到解决。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-07
    • 1970-01-01
    • 2012-10-03
    • 1970-01-01
    相关资源
    最近更新 更多