为什么会出现这种情况?使用 Windows WSL(ubuntu 20.04) 时的 c 库问题

Why this situation was happen? c lib problem while using Windows WSL(ubuntu 20.04)

我在 strcpy 和 strtol 函数中对 c lib 使用 gcc 时遇到一个奇怪的问题。 测试两种情况,得到截然不同的结果。

//#The bad code is "res=68"
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>

int main() {
    char buf[10];
    
    char* endptr;
    int x;
    int res;

    memset(buf, 0, sizeof(buf));
    res=0;

    strcpy(buf, "a678b");
    while (*(buf) != '[=12=]') {
        x = strtol(buf, &endptr, 10);
        if (x == 0) {
             
            strcpy(buf, (endptr + 1));
            
        }
        else {
            strcpy(buf, endptr);
        }
        res+= x;
    }
    printf("%d", res);
    return 0;
}

改成如下区域后,可以得到正确的值:678。 但是,为什么?

while (*(buf) != '[=13=]') {
        x = strtol(buf, &endptr, 10);
        if (x == 0) {
            memset(kk, 0, sizeof(kk)); // add this  
            strcpy(kk, (endptr + 1));// add this
            strcpy(buf, kk);
        }
        else {
            strcpy(buf, endptr);
        }
        res+= x;
    }

strcpymemcpy和朋友的调用不允许使用重叠的内存。如果内存重叠,则行为未定义。对于像您这样的短副本,由于一次复制多个字节的优化,这很可能会产生奇怪的结果。

有一个专为重叠记忆设计的函数,叫做memmove

但是,您根本不需要使用这些功能。我已经在下面更新了您的程序,只需通过您的字符串遍历指针即可实现此目的。好像没必要一直复制回buf.

开头
#include <stdio.h>
#include <stdlib.h>

int main()
{
    char buf[10] = "a678b";
    int res = 0;

    for (const char *s = buf; *s != '[=10=]'; )
    {
        char* endptr;
        int x = strtol(s, &endptr, 10);
        if (s == endptr)
          ++endptr;
        else
          res += x;
        s = endptr;
    }

    printf("%d", res);
}

此程序产生输出:

678

另请注意,我更改了 strtol 不读取数字时的测试。 return 值 0 可以完全有效。测试它是否真的解析了一个数字的正确方法是检查 endptr 是否超过了字符串的开头。

我还把res初始化为0,因为在你的程序中你在给它加值之前没有初始化它。这也是未定义的行为。

总而言之,由于滥用标准库函数和未初始化内存,您的程序中存在一些未定义行为的情况。