LINUX.ORG.RU

вопрос по поинтеру в С


0

0

все-таки поинтеры в С это засада (ну для меня так точно!).
Народ, помогите уразуметь!

/*декларирую*/
char* p = NULL;
void foo(char** pp);

/*где-то в main*/
foo(&p);


/*----------------*/
void foo(char** pp)
{
*pp = "kuku";
}

это верно в С???

anonymous

Нет.

Ты присваиваешь по поинтеру, который никуда не указывает. Если требуется выделять динамически используй strdup :

*p = strdup ("kuku")

Можно конечно *alloc и memcpy. Strdup тоже самое только вместе. Или используй статическое выделение : char p[4]

anonymous
()

Re:

> /*декларирую*/ > char* p = NULL;

- Ну декларируешь! Все Ок!

> void foo(char** pp) > { > *pp = "kuku"; > }

- а вот такое делать нельзя, такое можно делать при декларации, например: char* p = "kuku";

В иных случаях: p = strdup("kuku");

И то, тут не все так просто.

Функция strdup выделяет память ложит туда "kuku", присваевает значение указателя на эту память переменной p.

Теперь, если подругому: воспользоваться функцией strcpy (сделать копию "kuku" в память на которую указывает p):

pp = strcpy(p, "kuku");

То получим, если не сразу, то позже, кучу головной боли. Поскольку:

- мы не выделяли память для p (p = malloc(чего-то));

- не факт, что если и выделяли, то выделили ее достаточно чтобы вместить "kuku" (это программист сам отслеживает)...

Одним словом, не зря говорят, что С это платформонезависимый ассемблер :-)

Нарабатывай експириенс. И не забывай, что память выделенную в программе (malloc'ом и т.п.) надо освобождать (free).

LegaT
()

Для компилятора все верно, правда если он немного умнее он может обратить твое внимание на проблемы с памятью. Кроме того при запуске будет нарушение границ памяти и программа аварийно завершится.

А вообще ты фигню какую то написал ...

anonymous
()
Ответ на: комментарий от anonymous

>программа аварийно завершится.

не факт

anonymous
()
Ответ на: комментарий от anonymous

Хотя про границ с памятью я прогнал :). Все будет работать... но так писать низя, лучше бы поинтер бы возвращался из функции так будет лучше.

anonymous
()

Re:

> Хотя про границ с памятью я прогнал :). > Все будет работать... Ну, если поинтер вылезет за границы памяти процесса, то все нафиг свалится в Сегментэйшен Фолт.

А если всеж таки попадет в память процесса, то... Поведение программы не предсказуемо.. Возможно, что и работать будет.

LegaT
()

дык я почему и спросил - эта байда работает (SunOS 5.8 / GCC 2.8.1)
да и поймал я эту багу лишь профайлером (память-то течет тут).
ну пример в вопросе - есть сильно упрощенная моделька реального кода, который (повторюсь) работает!

anonymous
()

Это абсолютно корректно в C.
И утечек тут никаких нет.
Формально имеем переменную p.
На начальное значение типа NULL просто чхать.
Передаем адрес данной переменной в подпрограмму.
Внутри подпрограмы устанавливаем переменную (не что-нибудь еще!)
в адрес глобальной константы kuku.
Вот только далее могут быть грабли.
Если kuku размещена в text-секции,
то p[0] = 'a' может привести к segmentation fault,
если нет, то глобальная константа kuku станет auku.
Пример:
#include <stdio.h>
char *p=NULL;
main(){
foo(&p);
p[0] = 'a';
printf("%s\n",p);
foo(&p);
printf("%s\n",p);
}

foo(char **p){
*p = "kuku";
}
Если скомпилировать это на SPARC следующим образом:
gcc -o xixi xixi.c
то программа получить segmentation fault, если
gcc -o xixi -fwritable-strings xixi.c
то на экране получим два auku.
А вот исходя из этого, желающие могут возвращать указатель,
делать malloc/strdup и т.п. Это уже зависит от требований.
Особенно хорошо возвращать указатель в стиле return "kuku",
пример с fault почти не измениться.

Более интересно использовать следующий код:
foo(char **p){
char x[] = "kuku";
*p = x;
}
В этом случае можно никакого -fwritable-strings не писать и даже получить на экране auku и kuku.
Но такой способ является криминальным, он может не работать, т.к.
возвращается массив в стеке. Достаточно чуть удлинить kuku и
на экране получаем полную отсебятину (SPARC).

foo(char **p){
static char x[] = "kuku";
*p = x;
}
В этом случае опять же ключи не нужны, криминала нет, мы работаем
со статическими данными и имеем два auku.

io ★★
()

Re:

Блин! А ведь и в самом деле!!! Щас специально в K&K слазил посмотрел на счет "*p = "kuku";" - можно так делать оказывается, а я-то заблуждался! Век живи век учись.

А можно ссылочек на толкования С99?

LegaT
()

Абсолютно корректный код. Чё все так развонялись-то?

anonymous
()

нда...
io спасибо за разъяснения!
реально ситуация несколько сложнее
/*main*/
char *p = NULL;
foo1(&p1);

void foo1(char** pp)
{
char *dummy_p =NULL;

foo2(&dummy_p);

if (some_weired_cond)
{
*pp = dummy_p;
}
else
{
*pp="mumu";
}

}

void foo2(char** pp2)
{
robust_malloc(pp2, SOME_CONST, SOME_INITIAL_VALUE);
strncpy(*pp2, "kuku"); /*на самом деле тут не kuku а тоже строка из другой функции*/
}

вот такая длинная вложенная байда... но в принципе это ничего не меняет
спасибо!

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.