Я пытаюсь реализовать общий стек в 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;
}
Off теме: ПОЗДРАВЛЯЮ для документирования API! Могу ли я предложить, чтобы вы заменили эти значения успешных/неудачных возвратов '0' и' -1'? Если вы возвращаете '0' для отказа и' -1' (или любое другое ненулевое значение) для успеха, вы можете иметь несколько более интуитивные тесты: '! Stack_init (...)' будет означать неудачу, а не успех (зачитывать '!' как "не"). – stakx
@stakx: Я тоже так думал, но в будущем, если я хочу вернуть определенные коды ошибок вместо нуля для ошибки, можно использовать разные ненулевые значения. Как 1 для памяти, 2 для недействительной операции, -1 для любой другой ошибки и т. Д. И ноль означает успех. –
Достаточно честно! (Пока вы определяете константы или '# define' для этих значений ошибок ... :) – stakx