LINUX.ORG.RU

Определение типа. Как реализовать?


0

0

Собственно, есть функция (простейший пример), которая устанвливает значение переменной. Надо реализовать: если в функцию передается указатель на какой-либо тип, и если он не инициализирован -- выделить ему память и установить значение, если же передается адрес переменной -- просто установить значение. Проблема в том как это определить.

Нижеследующая программа, которая по-идее должна решать данную задачу, падает с ``segmentation fault''. Где ошибка? Спасибо.

===
#include <stdio.h>
#include <stdlib.h>



void set(int *p, int value)
{
if(p == NULL) p = (int *)malloc(sizeof(int));
*p = value;
}



int main(void)
{
int *q1 = NULL;
int q2 = 0;

set(q1, 10);
set(&q2, 20);

printf("q1: %i\n", *q1);
printf("q2: %i\n", q2);

free(q1);

return 0;
}
===

★★★

У тебя set пытается изменить указатель. У нее не получается. Не получается потому, что указатель она при этом получает по значению. В main q1 как указавал на NULL, так и будет это делать до тех пор, как ты не вызовешь free, вызвав тем самым segmentation fault.

Два варианта: передавать указатель на указатель или возвращать новое значение указателя из функции.

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

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

Собственно, у меня есть массив вида:
cfgStruct [] = {
{ "string1", ENUM_TYPE, &value1 },
{ "string2", ENUM_TYPE, value2 },
...
}

Сам cfgStruct есть что-то вроде этого:
struct cfgStruct{
char *keyword;
ENUM_TYPE type;
void *value;
};

И передается этот массив в функцию, которая будет изменять его. Поэтому очень важно, что если вместо ``void *value'' будет ``int *v'' или ``int v''. Если будет последнее, то он попытается выделить для него память и будет крах программы.

kondor ★★★
() автор топика
Ответ на: комментарий от kondor

> Собственно, у меня есть массив вида:

Рад за тебя. Ну и что? Ты не понял, что было написано в предыдущем посте, или просишь совета по дизайну? Во втором случае сформулируй вопрос по-другому, потому что непонятна проблемы: ну массив, ну функция должна действовать в зависомости от type, ну ... и что? ;)

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

``C'' я только учу, и мне совсем понятно, как сделать, что бы из функции можно было менять указатель.

kondor ★★★
() автор топика
Ответ на: комментарий от kondor

Ну ты же знаешь как вернуть указатель, правда? Вот и воспользуйся этим вариантом.

void *set (void *p, ...)
{
if (...)
 p = malloc(...);
return p;
}

main()
{
int *x;
x=set(x, ...)

}

А передача в функцию указателся на указатель выглядит так же, как и уазателя на привычный для тебя тип

vois set (void **p, ...)
{
if (...)
   *p = malloc(...)
}

main()
{
int *x;
set(&x, ...);
}

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

Спасибо за примеры и помощь. Вроде уяснил решение проблемы. Только все-равно мне не понятен смысл указателя-значения.

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

А как быть с этой функцией set (второй вариант), если туда необходимо передать просто int?

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

Честно говоря, дальнейшие попытки объяснений мне кажутся менее полезными, чем чтение книжек и эскперименты. В качестве утешения могу сказать, что указатели и связанные с ними вещи наиболее сложны для восприятия свежего человека.

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

Вот, например, у меня в справочники по Си Г. Шилдта не сказано, что в функциях нельзя изменять указатель. А Вы говорите книжки...

kondor ★★★
() автор топика
Ответ на: комментарий от kondor

Просто нужно усвоить одну вещь, в C параметры передаются только по значению (хотя хз, может быть можно и как в С++ через & объявлять и передавать по ссылке, не помню, ну ладно, не важно), поэтому всё, что нужно изменить передаётся как указатель. Например надо изменить переменную a:
void f(int* x)
{
*x = 3;
}
..
int a;
f(&a);

С ссылкой то-же самое, нужно передавать адрес тех байтов памяти где хранится эта ссылка, т.е.
void f(int** x)
{
*x = (int*)malloc(sizeof(int));
**x = 2;
}

int* a;
f(&a);

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

Legioner, спасибо большое! Я теперь понял, почему у меня не работали мои старые программы ;).

ВСЕМ СПАСИБО ЗА ПОМОЩЬ!

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