使用Realloc时,缩小个人实施中的堆栈崩溃
在个人实现数据结构中,我正在遇到缩小堆栈大小的问题。
我想是由于realloc()
的不良使用。执行时(spop()
,empty()
)(如果我删除realloc
并减少元素的数量,则工作正常),程序刚刚结束(崩溃)。
在实施中使用该功能的更好方法是什么,或者问题可能是什么?
stack.h
/*Stack.h*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
typedef struct Stack{
char **storage; //Elements container;
size_t capacity; //Total amount of elements POSSIBLE in the stack;
size_t size; //Total amount of elements within the stack;
}Stack;
Stack *salloc(size_t);
void spush(Stack *, char *);
char *spop(Stack *);
void speek(Stack *);
void empty(Stack *);
void print_stack(Stack *); //Useful but non-conventional
stack.c
/*Stack.c*/
#include "stack.h"
Stack *salloc(size_t size){
Stack *s = (Stack *)malloc(sizeof(s));
s->storage = (char **)malloc(sizeof(char *) * size);
s->capacity = size;
s->size = 0;
}
static int expand_stack(Stack *s){
s->storage = realloc(s->storage, (s->capacity * 2));
}
static void shrink_stack(Stack *s){
s->storage = realloc(s->storage, (s->capacity / sizeof(char *)));
}
void spush(Stack *s, char *elem){
char *p = elem;
int k = (s->capacity-1) - s->size; //Next free position
if(s->size == s->capacity)
expand_stack(s);
s->storage[k] = (char *)malloc(sizeof(char) * (strlen(p) + 1));
memcpy(s->storage[k], p, (strlen(p) + 1));
// *(s->storage[k] + (strlen(p) + 1)) = '\0';
s->size++;
}
char *spop(Stack *s){
int k = s->capacity - s->size;
if(s->size == 0)
return NULL;
free(s->storage[k]);
s->size--;
shrink_stack(s);
}
void speek(Stack *s){
int k = s->capacity - s->size;
printf("'%s'\n", s->storage[k]);
}
void empty(Stack *s){
s->storage = realloc(s->storage, 0);
s->capacity = 0;
s->size = 0;
}
void print_stack(Stack *s){
printf("[STACK] = {\n");
int k = s->capacity - s->size;
for(int i = k; i <= s->capacity-1; i++)
printf(" '%s'\n", s->storage[i]);
printf("}\n");
}
main.c
#include "stack.h"
#define COM1 "echo"
#define COM2 "start"
#define COM3 "sort"
int main(){
Stack *s = salloc(5);
spush(s, COM1);
spush(s, COM2);
spush(s, COM3);
// speek(s);
print_stack(s); //Full Stack
spop(s);
print_stack(s);
spush(s, "cd");
print_stack(s);
empty(s);
print_stack(s);
}
I am experiencing a problem in shrinking the size of a stack in a personal implementation of the data structure.
I suppose is due to bad usage of realloc()
. When the execution comes it (spop()
, empty()
) (If I remove the realloc
and decrement the number of elements, the implementation works fine), the program just ends (crash).
What would be a better way to use the function in my implementation, or what might the problem be?
stack.h
/*Stack.h*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
typedef struct Stack{
char **storage; //Elements container;
size_t capacity; //Total amount of elements POSSIBLE in the stack;
size_t size; //Total amount of elements within the stack;
}Stack;
Stack *salloc(size_t);
void spush(Stack *, char *);
char *spop(Stack *);
void speek(Stack *);
void empty(Stack *);
void print_stack(Stack *); //Useful but non-conventional
stack.c
/*Stack.c*/
#include "stack.h"
Stack *salloc(size_t size){
Stack *s = (Stack *)malloc(sizeof(s));
s->storage = (char **)malloc(sizeof(char *) * size);
s->capacity = size;
s->size = 0;
}
static int expand_stack(Stack *s){
s->storage = realloc(s->storage, (s->capacity * 2));
}
static void shrink_stack(Stack *s){
s->storage = realloc(s->storage, (s->capacity / sizeof(char *)));
}
void spush(Stack *s, char *elem){
char *p = elem;
int k = (s->capacity-1) - s->size; //Next free position
if(s->size == s->capacity)
expand_stack(s);
s->storage[k] = (char *)malloc(sizeof(char) * (strlen(p) + 1));
memcpy(s->storage[k], p, (strlen(p) + 1));
// *(s->storage[k] + (strlen(p) + 1)) = '\0';
s->size++;
}
char *spop(Stack *s){
int k = s->capacity - s->size;
if(s->size == 0)
return NULL;
free(s->storage[k]);
s->size--;
shrink_stack(s);
}
void speek(Stack *s){
int k = s->capacity - s->size;
printf("'%s'\n", s->storage[k]);
}
void empty(Stack *s){
s->storage = realloc(s->storage, 0);
s->capacity = 0;
s->size = 0;
}
void print_stack(Stack *s){
printf("[STACK] = {\n");
int k = s->capacity - s->size;
for(int i = k; i <= s->capacity-1; i++)
printf(" '%s'\n", s->storage[i]);
printf("}\n");
}
main.c
#include "stack.h"
#define COM1 "echo"
#define COM2 "start"
#define COM3 "sort"
int main(){
Stack *s = salloc(5);
spush(s, COM1);
spush(s, COM2);
spush(s, COM3);
// speek(s);
print_stack(s); //Full Stack
spop(s);
print_stack(s);
spush(s, "cd");
print_stack(s);
empty(s);
print_stack(s);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您的第一个
malloc
呼叫仅为stack*
分配足够的空间,对于实际stack
结构没有足够的空间。您想要:或
Your first
malloc
call only allocates enough space for aStack*
, not enough space for the actualStack
structure. You want:or
您的代码中有很多问题:
salloc
缺少返回S
。spop
不返回任何东西(除null
案例外)。salloc
没有为stack
object(sizeof(s)
分配足够的内存/代码>对象)。s-&gt; storege = realloc(...)
-realloc
(void*
)的结果应将其施放到char **
。Expand_stack
被定义为返回int
,但实际上什么都没有返回。可能应该更改为返回void
。shink_stack
未正确计算大小。结果,在您的情况下,realloc
实际上可以分配0尺寸的内存(注意::这是print_stack
中违反访问的原因。调用spop
之后)。我建议您使用调试器捕获此错误。There are quite a few issues in your code:
salloc
is missingreturn s
.spop
does not return anything (except for theNULL
case).salloc
is not allocating enough memory for aStack
object (sizeof(s)
is the size of the pointer, not theStack
object).s->storage = realloc(...)
- the result fromrealloc
(void*
) should be cast tochar**
.expand_stack
is defined to return anint
but nothing is actually returned. Should probably be changed to returnvoid
.shrink_stack
is not calculating the size properly. As a result in your caserealloc
can actually allocate a 0 size memory (Note:: this is a cause for an access violation exception inprint_stack
after callingspop
). I suggest you use a debugger to catch this bug.这里有很多问题。无论是在设计还是实施方面,但所有值得学习的课程。
以下是更改的摘要:
salloc
- 我们应该存储初始容量。空
只是释放所有存储,这会使堆栈无法使用。通过存储初始容量,shink_stack
可以避免在其下方收缩。Expand_stack
-容量
必须在扩展后进行修改,否则我们将失去对实际分配的跟踪。另外,如果没有问题,我们将无法超越初始容量。通过int
返回,我怀疑您打算返回新容量(应该是size_t
。shink_stack
不应该只保留划分容量,或者我们最终达到零,因此使用initial_capacity
我们将事情保持在一开始时也不需要缩小。所以。spush
- 我不知道为什么您选择从存储末端分配,但是当容量增加和扩张发生时,这从根本上讲会破裂。根据尺寸添加的简单得多,然后从大小回到零。请注意,添加了const
,或者某些编译器会抱怨将非const指针传递给字符串文字,这很危险。spop
- 根据spush
,size -1
返回零。这里的另一个错误是字符串存储在malloc'd缓冲区中,因此我们应该释放它,这意味着我们不能只返回指针,而是需要spop
签名来提供可以放置的缓冲区和最大尺寸。鉴于我们正在处理零终止字符串,因此可以是strncpy
。请注意,返回值是传递的地址,如果没有弹出元素,则null。也许还有其他方法可以帮助消除elem == null等的风险。。
speek
- 同样,只需使用size -1
empty
- 使用spop
即可删除所有元素而无需丢弃初始容量存储。print_stack
- 从零到大小。There's a lot of problems here. Both in design and in implementation, but all lessons worth learning.
Here are a summary of the changes:
salloc
- We should store the initial capacity.empty
was just freeing all storage which would make the stack unusable. By storing initial capacity,shrink_stack
can avoid shrinking below that.expand_stack
-capacity
must be modified after the expansion or we lose track of what the actual allocation is. Also, we wouldn't be able to add beyond the initial capacity without running into problems. Going by theint
return, I suspect you intended to return the new capacity (which should besize_t
.shrink_stack
should not just keep dividing the capacity, or eventually we hit zero. So using theinitial_capacity
we keep things no smaller than at the outset. It also needs to only shrink if the size has dropped to the point where there is value doing so.spush
- I don't know why you chose to allocate from the end of the storage but this fundamentally would break when the capacity increased and expansion occurred. Much simpler to add according to size, and pop off from size back towards zero. Note thatconst
is added or some compilers will complain about passing a non-const pointer to a string literal, which is dangerous.spop
- As perspush
, pop fromsize - 1
back towards zero. The other bug here was that the string is stored in a malloc'd buffer, so we should be freeing that, and that means we can't just return the pointer, but need thespop
signature to provide a buffer and max size in which to put it. Given that we are dealing with null terminated strings, this can be anstrncpy
. Note that the return value is the passed address, or NULL if there is no element to pop. There are other ways to perhaps handle this that help remove the risk of elem == NULL etc.speek
- Again, just usesize - 1
empty
- Usesspop
to remove all elements without discarding the initial capacity storage.print_stack
- From zero to size.