Я пытаюсь реализовать общий стек (отдельный список), я разработал все, кроме случаев, когда мне приходится обрабатывать массивы символов.Общая функция для копирования char * в C
Узел:
typedef struct cvor {
void *info;
struct cvor *next;
} Cvor;
стек ЬурейеЕ:
typedef struct {
Cvor *tos;
size_t velicinaInfo; //
freeFunction freeFn;
copyFunction copyFn;
} Stek;
функция для инициализации нового стека:
void noviStek(Stek *stek, size_t velInfo, freeFunction freeFn, copyFunction copyFn)
{
if (velInfo <= 0)
{
// element size can't be <=0
printf("Velicina elementa ne moze biti 0.\n");
return;
}
stek->tos = NULL;
stek->velicinaInfo = velInfo;
stek->freeFn = freeFn;
stek->copyFn = copyFn;
}
freeFunction
и copyFunction
определены следующим образом:
typedef void (*freeFunction)(void *);
typedef void (*copyFunction)(void **, void *);
Для примитивных типов (int
, double
, ...) Мне не нужна специальная функция копирования, но мне она нужна для char *. Это то, что я до сих пор:
void copyString(void **dest, void *src)
{
char *psrc = (char*) src;
size_t size = strlen(psrc) + 1;
*dest = calloc(size, 1);
memcpy(*dest, src, size);
}
основные выглядит следующим образом:
char a[] = "helloooooooooo";
char b[] = "helloworld";
char c[] = "stringst";
Stek s;
noviStek(&s, sizeof(char*), NULL, copyString);
push(&s, a);
printf("tops: ");
stekTop(&s, pisi_string);
printf("\n");
push(&s, b);
printf("tops: ");
stekTop(&s, pisi_string);
printf("\n");
push(&s, c);
printf("tops: ");
stekTop(&s, pisi_string);
printf("\n");
//char d[100] = "";
char d[]="";
while (pop(&s, d))
{
printf("d = %s ", d);
}
isprazniStek(&s);
stekTop()
печатает вершину стека, isprazniStek()
освобождает стек.
Выход:
tops: helloooooooooo
tops: helloworld
tops: stringstring
d =
d =
d =
Таким образом, если copyFn
определен, он используется, когда push()
и pop()
призваны скопировать информационное содержимое узла (для примитивных типов copyFn
является NULL
).
Проблема с функцией pop
, вот функция:
int pop(Stek *stek, void *element)
{
if (isEmptyStek(stek))
return 0;
Cvor *p = stek->tos;
if (stek->copyFn)
{
stek->copyFn(&element, p->info);
}
else
{
memcpy(element, p->info, stek->velicinaInfo); // element = p->info;
}
stek->tos = p->next;
if (stek->freeFn)
{
stek->freeFn(p->info);
}
free(p->info);
free(p);
return 1;
}
Он не копирует p->info
в element
(это происходит, когда я использую push()
), и это не освобождает p=info
.
Я не могу понять, почему. Извините, за длинную статью. Любая помощь приветствуется.
EDIT: Я изменил d
в главной функции от char d[]=""
к char *d
, теперь выход:
tops: helloooooooooo
tops: helloworld
tops: stringstring
d = (null)
d = (null)
d = (null)
EDIT2: Потому что мне нужно изменить d
Мне нужно отправить его адрес , вот правильный код:
char d[]="";
while (pop(&s, &d))
{
printf("d = %s ", d);
}
и соответствующее исправление в pop()
:
int pop(Stek *stek, void *element)
{
if (isEmptyStek(stek))
return 0;
Cvor *p = stek->tos;
if (stek->copyFn)
{
stek->copyFn(element, p->info); // <= !
}
...
EDIT3: Переменная d
должен быть освобожден отдельно, чтобы избежать порей (спасибо VALGRIND):
char d[]="";
while (pop(&s, &d))
{
printf("d = %s ", d);
// do something else with it
// ...
free(d);
}
Ваш код цикла «pop» выдал правильный результат. Почему вы говорите, что 'pop' не работает? Кроме того, не следует «char d [] =« ";' be 'char * d;'? Вы не можете перемещать или изменять размер массива! –
Предполагается изменить значение переменной 'd'. То есть, поместите верхнюю часть стека в 'd'. –
@DavidSchwartz Вы правы. Я изменил его и обновил свой вопрос. Он устанавливает 'd' в значение null –