缓冲区上的 basename 进入分段错误

Kol*_*dar 1 c pointers strcmp

我现在正在调整,basename我遇到了一个非常奇怪的案例(至少对我而言)。这是代码:

char buffer[300];
char* p;

strcpy(buffer, "../src/test/resources/constraints_0020_000");
printf("%d\n", strcmp(basename("../src/test/resources/constraints_0020_000"), "constraints_0020_000")); //works as expected
printf("assert testBasename02");
printf("%d\n", strcmp(basename(buffer), "constraints_0020_000") == 0);
printf("done 1\n"); //goes in segmentation fault
printf("%d\n", strcmp(basename(&buffer), "constraints_0020_000") == 0);
printf("done 2\n"); //goes in segmentation fault
printf("%d\n", strcmp(basename(&buffer[0]), "constraints_0020_000") == 0);
printf("done 3\n"); //goes in segmentation fault
p = malloc(strlen("../src/test/resources/constraints_0020_000") +1);
strcpy(p, "../src/test/resources/constraints_0020_000");
printf("%d\n", strcmp(basename(p), "constraints_0020_000") == 0); //works as expected
free(p);
printf("all done\n");
Run Code Online (Sandbox Code Playgroud)

第一个strcmp完全例外;这是第二个让我困惑的问题:为什么缓冲区会出现分段错误?我试图以不同的方式对缓冲区进行编码,但结果是一样的。

我当然可以忍受这种行为,但是......我真的不明白basename如果我给他喂食 aconst char*或缓冲区(最后也是 a char*)有什么区别。

是否有文件解释这种行为?只有我吗?我试图寻找解释,但我找不到任何解释。

这是我电脑的规格(如果你需要的话):

  • 操作系统系统:Ubuntu 16.4(64位在Windows 10 64位虚拟化);
  • CPU(不是我认为有用):Intel® Core™ i5-3230M CPU @ 2.60GHz × 2;

Sou*_*osh 5

根据手册页

错误

在这些函数的 POSIX 版本的 glibc 实现中,它们修改它们的参数,并在使用静态字符串(如"/usr/". [...]

基本上,

 basename("../src/test/resources/constraints_0020_000")
Run Code Online (Sandbox Code Playgroud)

invokes 调用未定义的行为,因为这是尝试修改字符串文字。


注意:如手册页中所述,需要更改单词。读起来像,

在glibc的实现这些功能的POSIX版本,它们修改了参数,所调用未定义的行为时像一个静态字符串叫"/usr/"。[...]

分段错误是 UB 的副作用之一,但不是唯一的副作用。

FWIW,尝试修改字符串文字本身会调用 UB。引用C11,第 6.4.5 章,字符串文字

[...] 如果程序尝试修改这样的数组,则行为未定义。


编辑:

正如后续评论中所讨论的,另一个问题是缺少头文件。你需要有

  #include <libgen.h>
Run Code Online (Sandbox Code Playgroud)

添加以便获得basename()可用函数的前向声明。