C:从堆栈弹出的字符串被打印为垃圾值

C:从堆栈弹出的字符串被打印为垃圾值,c,C,我试图将方程式的元素(即数字系列、字母系列和运算符)分离成令牌,存储在堆栈中,以便在调车场算法中进一步使用 为此,我尝试在输入字符串的开头识别元素,然后继续识别,直到它到达可能的结尾。一旦完成,检查的字符串位将从输入中剪切并推送到堆栈上。算法的这一部分工作正常,直到我推它。出于某种原因,当我弹出堆栈中的每个元素并打印它们时,它们会显示为随机文本,通常伴有'�' 我不知道为什么 我已经为我找到的C使用了一个堆栈实现。这两个实现都不起作用,并给出了相同的问题,但下面的代码是用第一个实现(宏)编写的

我试图将方程式的元素(即数字系列、字母系列和运算符)分离成令牌,存储在堆栈中,以便在调车场算法中进一步使用

为此,我尝试在输入字符串的开头识别元素,然后继续识别,直到它到达可能的结尾。一旦完成,检查的字符串位将从输入中剪切并推送到堆栈上。算法的这一部分工作正常,直到我推它。出于某种原因,当我弹出堆栈中的每个元素并打印它们时,它们会显示为随机文本,通常伴有'�' 我不知道为什么

我已经为我找到的C使用了一个堆栈实现。这两个实现都不起作用,并给出了相同的问题,但下面的代码是用第一个实现(宏)编写的

我已经用输入测试了代码
321 AZERTY
。通常,在最后一行,它应该显示

AZERTY
321
但是,它显示

P�Hd�U
!^d�U
或者至少,这是上次执行时显示的内容。确切的内容看起来是随机的,但我不认为它超过了6个字符

#定义DECL_堆栈_类型(类型、名称)\
typedef struct stk##name###t{type*buf;size#t alloc,len;}*stk##name\
stk###名称stk###名称####创建(大小#初始大小){\
如果(!init_size)init_size=4\
s=malloc(sizeof(结构stk####名称###u t))\
如果(!s)返回0\
s->buf=malloc(sizeof(类型)*初始大小)\
如果(!s->buf){free(s);返回0;}\
s->len=0,s->alloc=init_size\
返回s;}\
int stk#######u push(stk###name s,type item){\
类型*tmp\
如果(s->len>=s->alloc){\
tmp=realloc(s->buf,s->alloc*2*sizeof(类型))\
如果(!tmp)返回-1;s->buf=tmp\
s->alloc*=2;}\
s->buf[s->len++]=项目\
返回s->len;}\
键入stk###name###u pop(stk###name s){\
tmp型\
如果(!s->len)中止()\
tmp=s->buf[-s->len]\
如果(s->len*2 alloc&&s->alloc>=8){\
s->alloc/=2\
s->buf=realloc(s->buf,s->alloc*sizeof(type));}\
返回tmp;}\
void stk######name##u delete(stk###name s){\
自由->基本自由度;自由度;}\
键入stk###name###u get(stk###name s){\
tmp型\
如果(!s->len)中止()\
tmp=s->buf[1]\
返回tmp\
}
#定义stk_空(!(s)->len)
#定义stk_大小((s)->len)
DECL_堆栈_类型(字符*,str)
void str_to_stk(字符*输入,stk_str输出){
while(输入[0]!='\0'){
if(isdigit((输入[0])){
int i=0;
char*buffer=(char*)calloc(strlen(输入)*sizeof(char),0);
而((isdigit(输入[i])| |输入[i]='.')&&input[i]!='\0'){
strncat(缓冲器和输入[i],1);
i++;
}
stk_str_push(输出、缓冲);
输入=输入+i;
自由(缓冲);
}
else if(isalpha(输入[0])){
inti=0;char*buffer=(char*)calloc(strlen(input)*sizeof(char),0);
while(isalpha(输入[i])&&input[i]!='\0'){
strncat(缓冲器和输入[i],1);
i++;
}
stk_str_push(输出、缓冲);
输入=输入+i;
自由(缓冲);
}
else if(等位运算符(输入[0])| |输入[0]=='(“| |输入[0]=')”{
字符缓冲区[2];缓冲区[0]=输入[0];缓冲区[1]='\0';
stk_str_push(输出、缓冲);
输入=输入+1;
}
否则{
输入++;
}
}
而(!stk_empty(output))printf(“%s\n”,stk_str_pop(output));
}
void main(){
char*input=“321 AZERTY”;
stk_str output=stk_str_create(20);
str_至stk(输入、输出);
}

虽然我不一定是编程新手,但我主要是在Java(不久前)上工作,尤其是在MATLAB上工作,并附带了一点Python(主要是numpy)。然而,说到C,我还是一个新手,我正在努力学习它,以备将来的大学项目和将来对开源项目的贡献。

在没有尝试查找此代码中的所有错误的情况下,这里有一个明显的问题,您将令牌推到堆栈上:

  stk_str_push(output, buffer);
  input = input+i;
  free(buffer);
您已经将令牌累积到动态分配的
缓冲区
,并将指向已分配存储的指针推送到堆栈上。但是,然后在该指针上调用
free
,这将终止动态分配的生存期。这意味着您刚刚推到堆栈上的指针不能再被取消引用,因为它现在指向已删除的对象。或者,更准确地说,它指向了边缘。这通常被称为“悬空指针”

在不再需要分配所包含的数据之前(如果不再需要弹出的值,则可能是在从堆栈中弹出数据之后),不能
free()
分配

此外,稍后在同一函数中,您将演示创建悬挂指针的另一种常见方法:

  char buffer[2]; buffer[0] = input[0]; buffer[1] = '\0';
  stk_str_push(output, buffer);

这里,
buffer
是一种自动分配,而不是动态分配。自动分配只在您离开包含声明的块之前有效,该块在您将指针推到堆栈上后不久结束。当您开始使用该指针时,
buffer
数组将早已消失,再次使堆栈上的指针无用。

什么是
stk\u stru\u push
?什么是
DECL\u堆栈类型
?请出示证件。问题很可能出在这里没有显示的代码中。也请阅读以下内容:
char*buffer=