2013-10-27 2 views
2

Я пытаюсь реализовать общий стек в C, используя указатели void. Это не что-то большое, просто для удовольствия и обучения. Он работает с int и float, как ожидалось. Но проблема, с которой я столкнулся, - это char *, т. Е. Строки. Он не копирует адрес строки, а пытается скопировать фактическую строку до 4 байтов (так как размер моего системного указателя составляет 4 байта).Общий стек в C с использованием указателя void, который не работает для строк

Как сообщить C, чтобы скопировать адрес строки, а не фактическую строку, если это возможно, с нарушением функциональности int и float, уже работающих?

Моя реализация до сих пор выглядит следующим образом,


typedef struct{ 
     int top; 
     void *data; 
     int capacity; 
     size_t ele_size; 
}stack_t; 

int stack_init(stack_t *s, int capacity, size_t ele_size) 
{ 
     /* Initializes the stack with the given capacity 
     * @param s: Pointer to stack_t type variable 
     * @param capacity: capacity of the stack to be created 
     * Returns : Zero if succesful in allocating memory to the stack, 
     *    -1 Otherwise 
     */ 
     s->top = -1; 
     s->capacity = capacity; 
     s->ele_size = ele_size; 
     s->data = calloc(s->capacity, s->ele_size); 
     if (s-> data != NULL || s->capacity == 0) { 
       return 0; 
     } else { 
       return -1; 
     } 
} 

int stack_push(stack_t *s, void *x) 
{ 
     /* Pushes an element on to the stack 
     * @param s: Pointer to stack_t type variable 
     * @param x: Value to Push on to the stack 
     * Returns : Zero if stack is not full when stack_push() is called, 
     *    -1 Otherwise 
     */ 
     if (stack_len(s) capacity) { 
       s->top++; 
       memcpy(s->data + s->ele_size * s->top, x, s->ele_size); 
       return 0; 
     } else { 
       return -1; 
     } 
} 

int stack_pop(stack_t *s, void *value) 
{ 
     /* Value that is popped from the stack is placed in value parameter, 
     * @param s: Pointer to stack_t type variable 
     * @param x: Pointer to a variable to store the value popped from the 
         stack 
     * Returns: Zero if stack is not empty when stack_pop() is called, 
     *    -1 Otherwise 
     */ 
     if (stack_len(s) > 0) { 
       memcpy(value, s->data + s->ele_size * s->top, s->ele_size); 
       s->top--; 
       return 0; 
     } else { 
       return -1; 
     } 
} 

Для полной реализации стека, пожалуйста, обратитесь here

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



#include"../src/stack.h" 

START_TEST(int_push_pop) 
{ 
     stack_t s; 
     int n = random() % 60267; 
     int *a = calloc(n, sizeof (int)); 
     ck_assert_int_eq(stack_init(&s, n, sizeof (int)), 0); 
     int i; 
     for (i = 0; i = 0; i--) { 
       int value; 
       int x = stack_pop(&s, &value); 
       ck_assert_int_eq(x, 0); 
       ck_assert_int_eq(value, a[i]); 
       x = stack_len(&s); 
       ck_assert_int_eq(x, i); 
     } 
     stack_clear(&s); 
     stack_destroy(&s); 
} 

END_TEST 

START_TEST(float_push_pop) 
{ 
/* similar to int_push_pop, so ignored here. */ 
} 

END_TEST 


START_TEST(string_push_pop) 
{ 
     stack_t s; 

     char *str = "stack overflow"; 
     stack_push(&s, str); 
     char **popval = malloc(sizeof(char *)); 
     stack_pop(&s, popval); 
     printf("%s\n", popval); 

     stack_destroy(&s); 

} 

END_TEST 


Suite* stack_suite() 
{ 
     Suite *s = suite_create("Stack"); 

     TCase *tc_int = tcase_create("int"); 
     /* Stack int data type Test Case*/ 

     TCase *tc_float = tcase_create("float"); 
     /* Stack float data type Test Case*/ 

     tcase_add_test(tc_int, int_push_pop); 
     tcase_add_test(tc_float, float_push_pop); 

     suite_add_tcase(s, tc_int); 
     suite_add_tcase(s, tc_float); 

     return s; 
} 


int main() 
{ 
     int number_failed; 
     Suite *s = stack_suite(); 
     SRunner *sr = srunner_create(s); 
     srunner_run_all(sr, CK_NORMAL); 
     number_failed = srunner_ntests_failed(sr); 
     srunner_free(sr); 

     return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 
} 

+0

Off теме: ПОЗДРАВЛЯЮ для документирования API! Могу ли я предложить, чтобы вы заменили эти значения успешных/неудачных возвратов '0' и' -1'? Если вы возвращаете '0' для отказа и' -1' (или любое другое ненулевое значение) для успеха, вы можете иметь несколько более интуитивные тесты: '! Stack_init (...)' будет означать неудачу, а не успех (зачитывать '!' как "не"). – stakx

+1

@stakx: Я тоже так думал, но в будущем, если я хочу вернуть определенные коды ошибок вместо нуля для ошибки, можно использовать разные ненулевые значения. Как 1 для памяти, 2 для недействительной операции, -1 для любой другой ошибки и т. Д. И ноль означает успех. –

+1

Достаточно честно! (Пока вы определяете константы или '# define' для этих значений ошибок ... :) – stakx

ответ

1

С stack_push() и stack_pop() функций принимают void* указатель, вам нужно будет передать указатель на массив символов (строка), которая должна быть нажата и не сам массив символов. например если вы объявить строку как

char str[] = "hello world"; 

вы должны вызвать функцию

stack_push(s,&str); 

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

  • Нет связанных вопросов^_^