C语言中无最大长度限制的不同长度元素填充缓冲区方案咨询
C语言动态长度字符串栈的实现修正
原问题代码
void push(struct Stack *stack, void *element) { if (stack->len < stack->size) { memcpy(stack->arr + stack->len * sizeof(stack->elem_size), element, strlen((char*) element)); printf("Pushed: %s\n", (char *)element); stack->len++; } else { printf("Stack is full.\n"); } } void display(struct Stack *stack) { char** arr = (char**) stack->arr; for (int i = 0; i < stack->len; i++) { printf("[%s]\n", stack->arr + i * stack->elem_size); } printf("Done\n"); }
核心问题分析
- 指针算术错误:
void*类型不支持直接进行指针算术,且sizeof(stack->elem_size)取的是elem_size变量自身的大小(比如size_t类型通常占8字节),而非元素的实际长度,导致元素存储位置计算完全错误。 - 字符串存储不完整:
memcpy仅复制了strlen(element)字节,未包含字符串终止符\0,后续打印会出现乱码。 - 遍历逻辑错误:
display中将stack->arr强制转为char**(指针数组),但实际我们是直接在缓冲区存储字符串内容,而非指针,且固定步长的指针偏移完全不适应动态长度的字符串。
解决方案:带长度前缀的缓冲区存储
要在固定大小的缓冲区中存储动态长度字符串,需在每个元素前存储其长度,以此准确定位每个元素的位置。同时调整Stack结构体,增加缓冲区已使用字节的偏移量跟踪。
调整后的Stack结构体
#include <stdio.h> #include <string.h> #include <stdlib.h> typedef struct Stack { void *arr; // 固定大小的缓冲区(比如1024字节) size_t size; // 缓冲区总大小(如1024) size_t len; // 元素个数 size_t offset; // 当前缓冲区已使用的字节偏移量 } Stack;
修正后的push函数
void push(struct Stack *stack, void *element) { char *str = (char*)element; size_t str_len = strlen(str); // 计算当前元素需要的总空间:长度前缀(size_t) + 字符串内容 + 终止符 size_t total_size = sizeof(size_t) + str_len + 1; // 检查缓冲区剩余空间是否足够 if (stack->offset + total_size <= stack->size) { // 写入长度前缀 *(size_t*)((char*)stack->arr + stack->offset) = str_len; // 复制字符串(含终止符) memcpy((char*)stack->arr + stack->offset + sizeof(size_t), str, str_len + 1); printf("Pushed: %s\n", str); stack->len++; stack->offset += total_size; } else { printf("Stack is full. Remaining space: %zu bytes\n", stack->size - stack->offset); } }
修正后的display函数
void display(struct Stack *stack) { size_t current_offset = 0; for (int i = 0; i < stack->len; i++) { // 读取当前元素的长度 size_t str_len = *(size_t*)((char*)stack->arr + current_offset); // 定位字符串起始地址 char *str = (char*)stack->arr + current_offset + sizeof(size_t); printf("[%s]\n", str); // 偏移到下一个元素的起始位置 current_offset += sizeof(size_t) + str_len + 1; } printf("Done\n"); }
关键调整说明
- 指针算术转换:将
void*转为char*进行指针偏移,确保按字节单位计算位置,适配动态长度元素。 - 长度前缀存储:在每个字符串前写入其长度,遍历可通过长度值准确定位下一个元素的起始位置。
- 完整字符串存储:复制时包含
\0终止符,保证字符串能正常打印和使用。 - 剩余空间检查:基于已使用偏移量计算剩余空间,而非元素个数,符合动态长度存储的需求。
内容的提问来源于stack exchange,提问作者Emily Soto
相关产品推荐
相关产品推荐

