4

在 Solaris 5.8 机器上,我有以下代码:

[非工作代码]

char *buf;
char *dir;
size_t psize;

psize = (size_t) 1024;
dir = getcwd(buf, psize);

在这台 unix 机器上,上述方法不起作用,并且在尝试运行程序时出现分段错误。仅当我之前声明dir 时才 buf有效:

[工作代码]

char *dir;
char *buf;
...
dir = getcwd(buf, psize);

当使用另一种风格的 Unix 时,例如 Mac OS X,我没有得到任何关于如何编写代码的似乎非常严格的规则。谁能解释上面的例子发生了什么?谢谢!

4

5 回答 5

6

这里来自getcwd(3)

描述
     getcwd() 函数复制当前工作的绝对路径名
     将目录放入 buf 引用的内存中,并返回一个指向 buf 的指针。
     size 参数是 buf 引用的数组的大小(以字节为单位)。

     如果 buf 为 NULL,则根据需要分配空间来存储路径名。
     这个空间稍后可能会被释放(3)。

那就是 - 设置完成buf时间NULLfree(3)完成dir时间;或者为自己分配空间buf(因为你告诉getcwd(3)你那里有 1K)。

编辑:

所以要清理一下,它是:

char *dir = getcwd( NULL, 0 );

if ( dir == NULL ) { /* handle error */ }
/* use dir */
free( dir );

或者

char buf[1024]; /* or allocate it with malloc(3) */

if ( getcwd( buf, 1024 ) == NULL ) { /* handle error */ }

/* use buf, DO NOT free it if it's on the stack or static, 
   only if malloc-ed */
于 2010-04-12T00:46:06.867 回答
4

POSIX 要求第一个参数是指向存储路径名的缓冲区的指针。Mac OS X、Linux、Solaris 和其他系统上存在的一个常见扩展是,如果第一个参数为 NULL,那么getcwd()将为您分配一个缓冲区供您使用malloc()——然后您将在使用完free()它时释放它。POSIX 允许此扩展,但不是必需的,因此您不应在可移植代码中依赖它。

在您的情况下,您将未初始化的值作为第一个参数传递给getcwd(). 如果它恰好等于 NULL,那么将分配一个缓冲区;如果它是其他一些无效指针,那么您可能会遇到分段错误。由于该值未初始化,因此它可以具有任何值,并且可能取决于声明的顺序。如果您打算在之前分配缓冲区,getcwd()则显式传入 NULL 值;没有必要为此声明一个变量。然而,更便携的解决方案是传递一个指向您自己的缓冲区的指针,而不是依赖这个扩展。

于 2010-04-12T01:05:04.587 回答
3

您只声明了一个指针,没有为 getcwd 分配任何要写入的内存。getcwd 不会为您分配内存。您需要调用 malloc 自己分配它。

于 2010-04-12T00:45:09.573 回答
2

您声明指针的顺序将决定它们在内存堆栈中的放置顺序。我的猜测是,从示例一但不是示例二buf中丢弃的地址开始存在缓冲区溢出。dir您的其他操作系统可能会默默地防止此错误或以不同方式处理它。

于 2010-04-12T00:44:55.217 回答
2

声明顺序无关紧要

char *getcwd(char *buf, size_t 大小);  

getcwd() 函数复制当前工作的绝对路径名
**buf** 指向的数组的目录,该数组的长度为**size**。

buf在使用它之前应该分配内存。

buf = malloc(length * sizeof(char));

Afterchar *buf;被执行,buf包含垃圾值,当getcwd()试图修改内存指向的 bubuf时,它会导致Segmentation Fault.

于 2010-04-12T00:45:10.077 回答