2016-05-11 17 views
0

Я пытаюсь реализовать общий стек (отдельный список), я разработал все, кроме случаев, когда мне приходится обрабатывать массивы символов.Общая функция для копирования 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); 
} 
+3

Ваш код цикла «pop» выдал правильный результат. Почему вы говорите, что 'pop' не работает? Кроме того, не следует «char d [] =« ";' be 'char * d;'? Вы не можете перемещать или изменять размер массива! –

+0

Предполагается изменить значение переменной 'd'. То есть, поместите верхнюю часть стека в 'd'. –

+0

@DavidSchwartz Вы правы. Я изменил его и обновил свой вопрос. Он устанавливает 'd' в значение null –

ответ

0

Код поппинг должно быть:

char *d; 

while (pop(&s, &d)) 
{ 
    printf("d = %s ", d); 
    free(d); 
} 

Функция pop записывает popped value в память, на которую указывает аргумент. Поэтому вы должны указать указатель на область, в которой вы пишете всплывающее значение. Передача d не годится, и не передается указатель на 1-байтовый массив символов.

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

+0

Пожалуйста, см. Мое третье редактирование, я написал то же самое. –

+0

@smrdo_prdo no, у вашей третьей редакции есть 'pop (& s, d)' –

+0

Извините, мой плохой ... –

Смежные вопросы