C и возрашение указателя

Все о программировании под *nix
Аватара пользователя
Silos
Неотъемлемая часть форума
Сообщения: 287
Зарегистрирован: 15 фев 2004, 19:04
Откуда: Belarus, Minsk
Контактная информация:

C и возрашение указателя

Сообщение Silos »

Собственно есть C, gcc и этот код:

Код: Выделить всё

#include <stdlib>
#include <stdio>

void ss(char *tr)
{
     tr = (char *)malloc(50);
     tr = "aaaa!";
}

int main(int argc, char **argv)
{
     char *ptr;
     ss(ptr);
     printf("%s", ptr);
     return 0;
}


Проблема заключается в том, что память выделяется, но изменить эту память не получается - printf печатает что угодно, то только не строку "aaaa!".
Как решить эту проблему?
PS Смотрел дебагером в main адрес в ptr один, в ss другой, но когда возвращается обратно в main адрес в ptr остается прежним.

xaep
Заглянувший
Сообщения: 5
Зарегистрирован: 31 дек 2004, 00:13

Сообщение xaep »

2Silos: у тебя в коде по крайней мере 2 ошибки. Во-первых, чтобы ss изменяла значение ptr в main, нужно его передавать не по значению, а по ссылке( void ss(char* &tr) ). А во-вторых, ты выделяешь память в ss и потом теряешь указатель на нее, соответственно не освобождаешь. ИМХО у тебя проблема в понимании способов передачи параметров, а также представления строк и работы с памятью в C.

Аватара пользователя
Silos
Неотъемлемая часть форума
Сообщения: 287
Зарегистрирован: 15 фев 2004, 19:04
Откуда: Belarus, Minsk
Контактная информация:

Сообщение Silos »

Вообще C я никогда не учил. А сейчас понадобилось.
Вот методом проб и ошибок написал окло 70% программы, но из за незнания как передать по ссылке застопорился.
В данном случае память можно не освобождать, ибо прграмма тестовая и очень быстро завершается. А как известно после завершения OS сама освободит занаятую память.
Проблемы понимания у меня нету, есть только проблема незнания:)
Спасибо!

Аватара пользователя
exe
Неотъемлемая часть форума
Сообщения: 860
Зарегистрирован: 28 ноя 2003, 21:08
Откуда: Минск

Сообщение exe »

Silos, Почитай хоть какую книжку по С.

Указатели, массивы и управление памятью описаны в любой их них.
Перед тем как писать программы на С это просто необходимо. Иначе
потом никто не разберется без больших трудностей.

Особенно код функции ss() страшен. Ты думал что

tr = "aaaa!";

занесет строку по адресу в tr? Это просто ужасная ошибка.

Аватара пользователя
red f0x
Неотъемлемая часть форума
Сообщения: 338
Зарегистрирован: 08 мар 2004, 01:41

Сообщение red f0x »

1. Коль скоро ss(char *tr) изменяет указатель, то её аргумент должен быть двойным указателем: char** tr.
Передача аргумента должна выглядеть так: ss (&ptr);
2. tr = "aaaa!"; - а это вообще страх господень...
Это не паскаль. Такое присваивание изменяет адрес, "содержащийся в указателе", а не то, на что указывает указатель. Для операций со строками есть целая толпа функций str*(), mem*().

xaep,
В С++ допустим т.н. ссылочный тип - (char& tr), к-й недопустим в C. (Усли речь шла об это?) Если речь шла о нём, то объявление ss (char* &tr) выглядит как-то странно... :wink:
Ну какая работа со строками может быть в языке, название которого является не строкой, а символом? (c) Sergue E. Leontiev

Аватара пользователя
Silos
Неотъемлемая часть форума
Сообщения: 287
Зарегистрирован: 15 фев 2004, 19:04
Откуда: Belarus, Minsk
Контактная информация:

Сообщение Silos »

Спасибо за помощь, разобрался!

exe, вот часть кода и код main.c для тестирования:

main.c

Код: Выделить всё

#include <stdlib>
#include <stdio>
#include "s_math.h"

int main()
{
   const char *inte = "int(f(x^2)d(x/2))";
   char *f_x, *d_x;
   s_int_parse(inte, &f_x, &d_x);
   printf("f(x) = %s\nd(x) = %s\n", f_x, d_x);

   free((void *)d_x);
   free((void *)f_x);

   return 0;
}



s_math.h

Код: Выделить всё

#ifndef S_MATH_H
#define S_MATH_H

int s_int_parse(const char *s, char **f_x, char **d_x);

#endif



s_math.c

Код: Выделить всё

#include <stdlib>

#include "s_string.h"

int s_int_parse(const char *s, char **f_x, char **d_x)
{
   char *pinte = malloc(s_len(s) - 4);
   int rc = s_cut(s, pinte, 4, s_len(s));
   char *ff_x = malloc(rc - 2);
   char *dd_x = malloc(rc - 2);
   char *gap = ")d(";
   rc = s_break_two(pinte, ff_x, dd_x, gap, 1);
   *f_x = (char *)malloc(rc - 2);
   *d_x = (char *)malloc(s_len((char *)d_x) - 2);
   (void)s_cut(ff_x, *f_x, 2, rc);
   (void)s_cut(dd_x, *d_x, 2, s_len(dd_x));

   free((void *)dd_x);
   free((void *)ff_x);
   free((void *)pinte);

   return 0;
}



По моему, этот код легко читаем:)

Аватара пользователя
exe
Неотъемлемая часть форума
Сообщения: 860
Зарегистрирован: 28 ноя 2003, 21:08
Откуда: Минск

Сообщение exe »

Silos, Тебе может и легко, ты его создавал. Но могу гарантировать, забудешь через пару месяцев.

Можно пожужжать :-) ? Это не издевательство, не указание на незнание, а просто code review. Вдруг задумаешся...

1. Где комментарии?
2. На некоторых платформах #include <malloc> пригодится
3. malloc возвращает void *, не везде есть преобразование (char *).
4. char *gap = ")g("; не смотрится
и так далее.

А самое главное, запуск из-под valgrind что говорит?
Я вижу 5 malloc, 3 free. А что valgrind --tool=memcheck говорит?

Можешь все мои комменты выбросить далеко, если не применимы.

Аватара пользователя
Silos
Неотъемлемая часть форума
Сообщения: 287
Зарегистрирован: 15 фев 2004, 19:04
Откуда: Belarus, Minsk
Контактная информация:

Сообщение Silos »

Код: Выделить всё

3. malloc возвращает void *, не везде есть преобразование (char *). 

Тоесть для правильности работы "везде" необходимо писать (char *)malloc?

Код: Выделить всё

2. На некоторых платформах #include <malloc> пригодится

А как это определить, где необходимо, а где нет?

1. Где комментарии?

Все их дикое количество было вырезано, что бы сюда запостить.
Не постить же 20 kb кода?
Меня один раз kife попинал за отсутствие таковых, так теперь коментирую, все что могу забыть, или же может быть полезно знать другому:)

4. char *gap = ")g("; не смотрится

Тоесть?

А самое главное, запуск из-под valgrind что говорит?
Я вижу 5 malloc, 3 free. А что valgrind --tool=memcheck говорит?


Код: Выделить всё

[silos@asakura s_lib]$ valgrind test
==2790== Memcheck, a memory error detector.
==2790== Copyright (C) 2002-2005, and GNU GPL'd, by Julian Seward et al.
==2790== Using LibVEX rev 1471, a library for dynamic binary translation.
==2790== Copyright (C) 2004-2005, and GNU GPL'd, by OpenWorks LLP.
==2790== Using valgrind-3.1.0, a dynamic binary instrumentation framework.
==2790== Copyright (C) 2000-2005, and GNU GPL'd, by Julian Seward et al.
==2790== For more details, rerun with: -v
==2790==
==2790==
==2790== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 12 from 1)
==2790== malloc/free: in use at exit: 0 bytes in 0 blocks.
==2790== malloc/free: 30 allocs, 30 frees, 1,981 bytes allocated.
==2790== For counts of detected errors, rerun with: -v
==2790== No malloc'd blocks -- no leaks are possible.
[silos@asakura s_lib]$ valgrind --tool=memcheck test
==2799== Memcheck, a memory error detector.
==2799== Copyright (C) 2002-2005, and GNU GPL'd, by Julian Seward et al.
==2799== Using LibVEX rev 1471, a library for dynamic binary translation.
==2799== Copyright (C) 2004-2005, and GNU GPL'd, by OpenWorks LLP.
==2799== Using valgrind-3.1.0, a dynamic binary instrumentation framework.
==2799== Copyright (C) 2000-2005, and GNU GPL'd, by Julian Seward et al.
==2799== For more details, rerun with: -v
==2799==
==2799==
==2799== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 12 from 1)
==2799== malloc/free: in use at exit: 0 bytes in 0 blocks.
==2799== malloc/free: 30 allocs, 30 frees, 1,981 bytes allocated.
==2799== For counts of detected errors, rerun with: -v
==2799== No malloc'd blocks -- no leaks are possible.
[silos@asakura s_lib]$


Можешь все мои комменты выбросить далеко, если не применимы.

Тише... Что мне давно не хватало, так это code review.
Вообщем то это хорошо.
Чем больше code review, тем лучше код!
:D :D
Вообщем было бы очень хорошо, если бы вы могли продолжить, я б исходники выслал бы, или бы выложил:)

Аватара пользователя
red f0x
Неотъемлемая часть форума
Сообщения: 338
Зарегистрирован: 08 мар 2004, 01:41

Сообщение red f0x »

exe, #include <malloc> ?
А откуда такое? malloc без .h как-то на С++ смахивает :D Или может имеется в виду #include <malloc> ? Нет, на самом деле, без иронии, интересно.

Silos, может я ошибаюсь, но мне кажется, что правила хорошего тона требуют, чтобы всё, что было захвачено, было и освобождено (когда оно уже не нужно). Т.е., другими словами, на каждый malloc() должен быть свой free().
Ну какая работа со строками может быть в языке, название которого является не строкой, а символом? (c) Sergue E. Leontiev

Аватара пользователя
red f0x
Неотъемлемая часть форума
Сообщения: 338
Зарегистрирован: 08 мар 2004, 01:41

Сообщение red f0x »

Рискну ответить сам себе по поводу первого... По непонятным причинам после malloc проглатывается точка h.....
Ну какая работа со строками может быть в языке, название которого является не строкой, а символом? (c) Sergue E. Leontiev

Аватара пользователя
exe
Неотъемлемая часть форума
Сообщения: 860
Зарегистрирован: 28 ноя 2003, 21:08
Откуда: Минск

Сообщение exe »

Вот и мой review накрылся :-) просто забыл .h

насчет везде (char *) - правило хорошего тона. С проглотит и не поморщится и без него.

char *gap используется один раз - либо выкинь, либо определи как
константу или #define вверху. Считается более читабельным.

Аватара пользователя
Silos
Неотъемлемая часть форума
Сообщения: 287
Зарегистрирован: 15 фев 2004, 19:04
Откуда: Belarus, Minsk
Контактная информация:

Сообщение Silos »

red f0x, на каждый malloc свой free.
Просто это кусок кода.

exe, действительно, лучше выкинуть - чавой то я записался совсем.....

Спасибо!

Аватара пользователя
exe
Неотъемлемая часть форума
Сообщения: 860
Зарегистрирован: 28 ноя 2003, 21:08
Откуда: Минск

Сообщение exe »

red f0x, Ты прав насчет malloc()/free(), но посмотри не вывод
valgrind - нету потери памяти. Значит у него где-то free() запрятан
при вызове других функций.

Silos, Будь осторожен с такими передачами - сложно уследить
за всеми указателями.

Аватара пользователя
Silos
Неотъемлемая часть форума
Сообщения: 287
Зарегистрирован: 15 фев 2004, 19:04
Откуда: Belarus, Minsk
Контактная информация:

Сообщение Silos »

exe, без осторожности и внимательности здесь никак.
Протестировал я свою программу valgrind'ом(это около 1000 строк) - утечек не было обнаружено. Это уже радует:)

Тут встал другой вопрос:
Необходимо сделать функцию наподобие printf() - зарание не известно сколько ей будет передано аргументов. Как реализовать?
Или же смотреть в сторону масивов указателей?

Аватара пользователя
exe
Неотъемлемая часть форума
Сообщения: 860
Зарегистрирован: 28 ноя 2003, 21:08
Откуда: Минск

Сообщение exe »

#include <stdargs>

extern void trPrintf(int flag, char *fmtStr, ...);
void trPrintf(int flag, char *fmtStr, ...)
{
va_list argP;
int save_errno = errno;

va_start(argP, fmtStr);
vsprintf(msgBuf, fmtStr, argP);
va_end(argP);

if (trPrintFunction == (traceHandler) NULL)
fprintf(stderr, "%s\n", msgBuf);
else
(*trPrintFunction)(msgBuf);

errno = save_errno;
}

Ответить