算法题:给定一个字符串,逐个翻转字符串中的每个单词,例如输入是"I am a student in Renmin University of China”,输出"China of University Renmin in Student a am I".(用栈实现)
算法思想:运用俩个栈实现一个特殊队列,遇到空格则将栈1的元素入到栈2里。
先看代码
#include
#include
#include
using namespace std;
#define OVERFLOW -2
#define OK 1
#define NO 0
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10
typedef int ElemType;
typedef struct SqStack
{
char *base;
char *top;
int stacksize;
} SqStack;
void Init_SqStack(SqStack &S)
{
S.base = (char *)malloc(sizeof(char));
if (!S.base)
exit(OVERFLOW); //分配失败
S.top = S.base;
S.stacksize = STACK_INIT_SIZE;
return;
}
void push(SqStack &S, char e)
{
if (S.top - S.base >= S.stacksize) //栈满追加空间
{
S.base = (char *)realloc(S.base, (S.stacksize + STACKINCREMENT) * sizeof(char));
if (!S.base)
exit(OVERFLOW);
S.top = S.base + S.stacksize;
S.stacksize += STACKINCREMENT;
}
*S.top++ = e;
return;
}
void Pop(SqStack &s, char &e)
{
if (s.base == s.top)
{
cout<<'error'<=1;i--)
{
char a=*(p+i-1);
cout<
这是正常运行的结果
这是 调试时候的输出结果
可以发现俩种途径得到输出不一样(人傻了)
后面重新改了一下reverse函数中的一部分发现运行结果和调试结果都是正确的,开始四处询问????????????????????
int isblank=0;//判断是否遇到空格
while(s[i]!='\000')
{
if (s[i] != ' ')
{
push(tmp, s[i]);//遇到字母入栈
i++;
}
else if (s[i] == ' ')//遇到空格表明一个单词已经入栈完
{ isblank=1;
push(tmp, ' ');
i++;
}
if(isblank==1)//遇到空格将单词出栈进入结果栈内
{
spread(tmp,result);
isblank=0;
}
}
push(tmp,' ');
spread(tmp,result);//处理最后一个单词
然后关于错误代码,尝试输出每次spread时候俩个栈的状态
以及找了一些例子测试
发现不管单词长短,凡是到了32位就发生了内存问题。
百思不得其解,后经过老师点拨发现问题。
我们回到初始化代码,貌似也没有问题。
仔细想了一下,俩次malloc(1)可能会引起内存问题。
我们发现c语言中俩次malloc(1)地址竟然相差32,这实际上是不同编译器/标准libriaries之间的实现细节。通常,无法保证随后的malloc
调用将返回相邻的内存区域。另请注意,每个内存区域都与其他元数据相关联,包括但不限于区域大小(否则,当运行free
时,无法知道要释放多少内存)。此元数据通常放在已分配的区域内,使其大于请求的大小。还有一些其他因素影响实际分配的内存量 - 内存对齐和malloc
实现使用的“漏洞”查找算法等。详见:jkt's blog: Tagged pointers, and saving memory in Trojita
解决方法:
1.通过在sizeof前乘以一个大于32的整数(一般选用50或者100),问题得到解决。
2.直接使用new来初始化空间。
一.参考DEBUG模式下, 内存中的变量地址分析 - findumars - 博客园
试验结论 - <
所以,之前 修改reverse函数后Debug和Release最后结果一致可能只是运气问题,不一定真的正确。
二.参考使用malloc遇到的奇怪问题——调试的时候正确,运行的时候结果就不对了 - Ash_boy - 博客园
稍微仔细一点的同学都能发现p = (struct A*)malloc(sizeof(struct A*));是不是看起来有点别扭?解释解释?首先malloc函数申请一块sizeof(struct A*)这么大的内存,然后将返回类型强制转换为struct A型的指针赋值给p。那么sizeof(struct A*)是多大呢?熟悉指针的人都知道一般是4个字节,实在不知道的话,进入调试状态在watch窗口输入sizeof(p),因为p为struct A*,其大小即struct A*大小。
问题已经非常明显了,我们要动态开辟一个struct A型的p,那么开创的空间肯定要和struct A一样大的,4字节够了吗?原来是多了一个*。更正以后运行,正确无误了。
问题是比较简单的,也是非常容易解决的。
但是,如果你忘记了free(不会报任何错误),而且你有将动态分配的p进行了很多其他的操作的时候,或者是在其他地方也动态开辟了内存的话。那么你会发现怎么这些数据都非常的奇怪,居然是凭空产生的,非常难以理解。明明是整个的思路,逻辑,语法都没错却有这样奇怪的结果。再回到前面的问题,我们只给p分配了4个字节,那么他是怎么访问结构体里面的100个int型的数据呢?这就不的不提起数组越界了。C是不对越界进行检查的,所以p中就如上面所提到的正确访问,正确赋值,正确输出。但是它访问的并不是它所拥有的空间,也就是其他变量的,如果其他变量进行其他操作的话,它的值也就变了。至于怎么变就不知道了。
参考debug模式的malloc_馋嘴猪没胃口-CSDN博客
我们每次申请一块内存,都会有额外的内存被分配,所以使用连续使用malloc可能会导致内存溢出。