Страница 1 из 2

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

Добавлено: 13 май 2006, 20:21
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 остается прежним.

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

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

Добавлено: 14 май 2006, 11:04
exe
Silos, Почитай хоть какую книжку по С.

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

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

tr = "aaaa!";

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

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

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

Добавлено: 20 май 2006, 21:07
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;
}

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

Добавлено: 20 май 2006, 21:51
exe
Silos, Тебе может и легко, ты его создавал. Но могу гарантировать, забудешь через пару месяцев.

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

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

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

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

Добавлено: 20 май 2006, 23:27
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
Вообщем было бы очень хорошо, если бы вы могли продолжить, я б исходники выслал бы, или бы выложил:)

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

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

Добавлено: 21 май 2006, 02:10
red f0x
Рискну ответить сам себе по поводу первого... По непонятным причинам после malloc проглатывается точка h.....

Добавлено: 21 май 2006, 11:12
exe
Вот и мой review накрылся :-) просто забыл .h

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

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

Добавлено: 21 май 2006, 13:24
Silos
red f0x, на каждый malloc свой free.
Просто это кусок кода.

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

Спасибо!

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

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

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

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

Добавлено: 21 май 2006, 17:14
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;
}