Действительно ли порядок, в котором я объявляю указатели, имеет значение в C? проблема с getcwd () - PullRequest
4 голосов
/ 12 апреля 2010

На машине 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, я не получаю ни одного из этих, которые кажутся очень строгими правилами написания кода. Может кто-нибудь объяснить, что происходит с приведенным выше примером? Спасибо!

Ответы [ 5 ]

6 голосов
/ 12 апреля 2010

Вот от getcwd(3):

DESCRIPTION
     The getcwd() function copies the absolute pathname of the current working
     directory into the memory referenced by buf and returns a pointer to buf.
     The size argument is the size, in bytes, of the array referenced by buf.

     If buf is NULL, space is allocated as necessary to store the pathname.
     This space may later be free(3)'d.

То есть - установите buf на NULL и free(3) на dir, когда закончите; ИЛИ выделите место для buf самостоятельно (поскольку вы говорите getcwd(3), что у вас там 1 КБ).

Edit:

Так что, чтобы немного почистить, можно либо:

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 */
4 голосов
/ 12 апреля 2010

POSIX требует, чтобы первым аргументом был указатель на буфер, в котором хранится имя пути. Распространенным расширением, которое присутствует в Mac OS X, Linux, Solaris и других, является то, что если первый аргумент равен NULL, то getcwd() выделит для вас буфер, используя malloc() - вы затем освободите его, используя free() когда вы закончите с этим. Это расширение разрешено POSIX, но не обязательно, поэтому вы не должны зависеть от него в переносимом коде.

В вашем случае вы передаете неинициализированное значение в качестве первого аргумента getcwd(). Если он окажется равным NULL, тогда будет выделен буфер; если это какой-то другой неверный указатель, вы можете получить ошибку сегментации. Поскольку значение неинициализировано, оно может иметь любое значение и зависеть от порядка объявления. Если вы намеревались выделить буфер getcwd(), то передайте значение NULL явно; для этого не нужно объявлять переменную. Однако более переносимым решением было бы передать указатель на ваш собственный буфер, а не полагаться на это расширение.

3 голосов
/ 12 апреля 2010

Вы только объявили указатель, вы не выделяли память для записи в getcwd. getcwd не выделяет память для вас. Вам нужно вызвать malloc, чтобы выделить его самостоятельно.

2 голосов
/ 12 апреля 2010

Порядок декларирования не имеет значения .

char *getcwd(char *buf, size_t size);  

The getcwd() function copies an absolute pathname of the current working 
directory to the array pointed to by **buf**, which is of length **size**.

buf должен быть выделен памяти перед его использованием.

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

После выполнения char *buf;, buf содержит значение мусора, а когда getcwd() пытается изменить память, указанную bu buf, это вызывает Segmentation Fault.

2 голосов
/ 12 апреля 2010

Порядок, в котором вы объявляете указатели, будет определять порядок их размещения в стеке в памяти. Я предполагаю, что существует переполнение буфера, начинающееся по адресу buf, который уничтожает dir в первом примере, но не в двух. Ваша другая ОС может молча предотвращать эту ошибку или как-то иначе ее обрабатывать.

...