Точно сказать не могу, но предполагаю, что прав
amaora: "/a/b/c/d" -- это не
char *, а
const char *.
А значит и располагается в памяти, которую можно только
читать
В отличии от функции
strdup, которая по
malloc распределяет новый фрагмент памяти и копирует в неё строку, указанную аргументом, функция
dirname модифицирует строку, на которую указывает аргумент.
Доказательством этого служит следующая программа:
Код: Выделить всё
#include <string.h>
#include <stdio.h>
#include <libgen.h>
int main( void ){
char *str = "/a/b/c/d";
char *cp = strdup( str );
printf( "dirname1 = %s\n", cp); // p.1
char *p1 = dirname (cp);
printf( "%p %p %p\n", str, cp, p1 ); // p.2
printf( "dirname2 = %s\n", cp); // p.3
fflush(stdout);
char *p = dirname( str ); // a.4
printf( "dirname = %s\n", p ); // p.5
return 0;
}
У меня она выдала следующий вывод:
dirname1 = /a/b/c/d
0x8048624 0x80497d0 0x80497d0
dirname2 = /a/b/c
Segmentation fault
Из этого вывода видно, что:
- Оператор p.1 напечатал полное значение начальной строки
- Оператор p.2 напечатал адреса строк str, cp и p1. Видно, что адрес у строк cp и p1 одинаковый
- Как подтверждение этого, оператор p.3 напечатал усечённный вариант первоначальной строки. Т.е. можно было просто написать dirname(cp); и дальше использовать cp, а не p.
- Оператор p.5 не выполнялся, т.е. Segmentation fault выскочило при выполнении оператора a.4.
Как вариант, можно было бы написать (правда, пока не проверил)
P.S. Решил посмотреть, что будет при использовании компилятора Open Watcom под Windows.
Результат получился другой. Правда, программу пришлось немного модифицировать -- компилятор не принимал объявления после исполняемых операторов
Программа получилась:
Код: Выделить всё
#include <string.h>
#include <stdio.h>
#include <libgen.h>
int main( void ) {
char *str = "/a/b/c/d";
char *cp = strdup( str );
char *p1, *p;
printf( "dirname1 = %s\n", cp);
p1 = dirname(cp);
printf( "%p %p %p\n", str, cp, p1 );
printf( "dirname2 = %s\n", cp);
fflush(stdout);
p = dirname( str );
printf( "dirname = %s\n", p );
return 0;
}
И её вывод:
dirname1 = /a/b/c/d
00408004 00360788 00409000
dirname2 = /a/b/c/d
dirname = /a/b/c
Т.е. строки
cp и
p1 имели
разные значения и программа нормально доработала до конца.
Видимо, в этой системе функция dirname возвращает указатель на свой внутренний массив типа char, в который и переносит строку-аргумент.
Доказательсвом этого служи предупреждение в help'е
The dirname function is not re-entrant or thread-safe., а также програииа
Код: Выделить всё
#include <string.h>
#include <stdio.h>
#include <libgen.h>
int main( void ) {
char *p1 = dirname("/a/b/c/d");
char *p2 = dirname("/x/y/z");
printf( "dirname1 = %s\n", p1);
printf( "dirname2 = %s\n", p2);
return 0;
}
И её вывод:
dirname1 = /x/y
dirname2 = /x/y
Т.е. после нахождения второго каталога первый теряется.
amaora писал(а): ↑10.08.2008 07:58
посмотрите ещё вот это,
Код: Выделить всё
int main( void ){
char str[] = "/a/b/c/d";
...
}
str здесь это массив символов, инициализированный статичной строкой. это похоже на strdup() только используется стековая память.
длину можно указать явно, это кол-во символов + 1 для завершающего 0-ля.
По-моему, тут не стековая, а обычная память (хотя... смотря что понимать под стековой памятью).
Компилятор просто размещает строку "/a/b/c/d" в области констант (указывая, что память будет RO), а её адрес заносит в область данных (память RW) в то место, где он разместил переменную str