关于栈的问题 救救小弟吧!

老拆 2020-03-19 07:53:15
这怎么总是触发一个断点 我还没太理解 所以 不知道怎么找断点 各位哥哥们 帮帮忙
...全文
174 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
ggglivw 2020-03-20
  • 打赏
  • 举报
回复
上面某些回复void printstack(sqstack *s) 暴露了太多内部细节,你看看了解一下原理就行,实际开发中不能这样写,你自己独立完成了一个list或者队列,不管好不好,先完成,哪怕你暴露了很多细节。 然后你再去看看std::list, std::deque的接口,思考下别个咋个暴露接口得,有没有暴露很多不应该你知道的细节,当然,现在要你懂std的东西也有点为难你,只是想让你感受下别个的思想,让你知道你和别个的差距在哪里。写代码一定要多写,多思考,思考很重要,如果不思考只会拷贝代码这条路走不长的
ggglivw 2020-03-20
  • 打赏
  • 举报
回复
引用 7 楼 m0_46472878 的回复:
[quote=引用 5 楼 ggglivw的回复:]接口没有定义好,push我就不说了,你至少pop得告诉别个操作结果吧,你如果都取出失败了,你能随便操作?

老哥,我是真的不太懂这个原理,所以就照着书上写的,一知半解 ,然后就这样了[/quote]

这个不是原理的问题,而是简单常识逻辑问题。你要取出某个东西(pop), 你得告诉别个一个结果,你取成功了还是取失败了。你不告诉结果,你让下一个逻辑如何执行?
老拆 2020-03-20
  • 打赏
  • 举报
回复
感觉好抽象,地址是干什么的,一直不明白
老拆 2020-03-20
  • 打赏
  • 举报
回复
引用 5 楼 ggglivw的回复:
接口没有定义好,push我就不说了,你至少pop得告诉别个操作结果吧,你如果都取出失败了,你能随便操作?
老哥,我是真的不太懂这个原理,所以就照着书上写的,一知半解 ,然后就这样了
老拆 2020-03-20
  • 打赏
  • 举报
回复
引用 5 楼 ggglivw的回复:
接口没有定义好,push我就不说了,你至少pop得告诉别个操作结果吧,你如果都取出失败了,你能随便操作?
老哥,我是真的不太懂这个原理,所以就照着书上写的,一知半解 ,然后就这样了
ggglivw 2020-03-20
  • 打赏
  • 举报
回复
接口没有定义好,push我就不说了,你至少pop得告诉别个操作结果吧,你如果都取出失败了,你能随便操作?
千梦一生 2020-03-20
  • 打赏
  • 举报
回复
引用 3 楼 m0_46472878 的回复:
[quote=引用 2 楼 m0_46472878的回复:][quote=引用 1 楼 yukint的回复:]你的原意是想用数组还是链表实现一个栈呢?,看你的意思是想用数组, 我根据你写的写个给你吧
真的C语言对于没有一些计算机基础的人,特别难,你唯一能做的是练习练习
关键还看懂的人,能不能讲到你懂位置,自己还要去体悟,理解需要一个过程
#include <stdio.h>
#include <stdlib.h>
/*数组实现栈*/
#define MAXSIZE 256
/*程序命名风格,要么都用大写开头,命名类型和函数,要么都用小写
与厦门的sqstack, pop等保持一致,不要混用两种风格
*/
typedef int elemtype;
typedef struct list
{
elemtype *bottom; //命名规范,bottom 对top,,high对low,,
elemtype *top; //既然想通过typedef 来方便修改类型就统一用这个,而不是int*
int capability; //栈的总容量,不是栈中元素个数
}sqstack;

/*
1 变量命名用小写,不要大写
2 sqstack *s 用指针, 就已经表示传的是地址了, 指针变量是变量的一种
都是这么定义的,而不是用&s
调用的时候才用取地址符号
比如 sqstack stack_test;
init(&stack_test)
*/
/*考虑到栈有建立,就要有响应的销毁过程与之对应
以便释放内存,这里将init改成create,
同时新增destroy函数*/

/*
return: 0成功, 1 失败
不要对同一个s重复调用,否则会内存泄漏
*/
int create(sqstack *s)
{
s->bottom = (elemtype *)malloc(MAXSIZE * sizeof(elemtype)); //*申请连续空间----,而不是申请一个
if(!s->bottom){ //等价于 if(s->bottom == NULL)
printf("malloc memory error\n");
return 1;
}
s->top = s->bottom; //指针访问成员,用箭头->,而不是.
s->capability = MAXSIZE;
return 0; //
}
/*要求使用者很小心,必须是成功create过的s,才能调用*/
void destroy(sqstack *s)
{
if(s->bottom) //bottom是不变的,用于记录申请的空间,
{
free(s->bottom);
s->bottom = NULL;
}
return;
}

int push(sqstack *s, elemtype e)
{
/*指针让人产生歧义的地方,有时候图方便,你会想当然的认为,要取栈顶元素,直接拿top就是了
* 事实上,要取栈顶元素的时候,是top-1,而不是top!!
* 既然top开始指向可放元素的地方,即入栈位置,那么他表示top入完栈之后,你把他加1, 显然top指示的是一个未知元素,,,
* 继续看后面的实现,就知道top指针多尴尬
*/
if(s->top - s->bottom == s->capability)
{
//栈满了,扩容
printf("stack full, realloc a larger space\n");
elemtype *new_ptr = (elemtype *)realloc(s->bottom, s->capability * 2);
if(new_ptr == NULL)//重新分配失败,原来的保留
{
printf("fail to realloc more memory\n");
return 1;
}
s->bottom = new_ptr;
s->capability = 2 * s->capability;
}

*s->top++ = e;
return 0;
}

/*
return : 0 ok, 1 err 栈为空,无法再弹出(pop)元素出来
*/
int pop(sqstack *s, elemtype *e)
{
if(s->top == s->bottom)
{
printf("stack is empty\n");
return 1;
}

*e = *--s->top;
return 0;
}
/*自顶向下打印栈*/
void printstack(sqstack *s)
{
/*
这里要减1,用简单情况进行推理
比如栈只有1个元素的时候,这个元素就在第0个位置
C语言连续内存,比如数组,总是从0开始
*/
if(s->top == s->bottom)
{
printf("stack is empty, nothing in it\n");
return;
}

printf("print stack s from top to bottom\n");
elemtype *itor = s->top; //因为只是打印,不要去改变这个栈,所以用临时变量来进行遍历
while (itor != s->bottom) //虽然是很不好的风格,,谁让你用指针呢, 而且指针绕到你头疼
{
/*这里假定elemtype 是int(用%d打印),这就是C语言麻烦的地方
先不多扯了,想想如果是double,是不是要另外写函数,
一般要用函数指针来实现,你先了解下就好*/

/*%d 后面有空格,2d表示用两个位置来打印一个数,
额额,如果3位数? 3d,如果不确定几位,那就不对齐了,,,
这里只是在对比的时候能对齐,好看*/
printf("%2d ", *--itor); //如果用 *--s->top;,,那你一边打印,一遍出栈了。。。
}
printf("\n"); //换行
}
/*反转栈
虽然这样写比较没效率,但是想象一下
你有一叠盘子,嗯,底下的盘子大,上面的盘子小
现在,你从顶部开始一个一个拿下来,一次叠到另外一个地方,想象一下
- ----
-- --> ---
--- --
---- -

*/
/*略去了错误处理,你可以考虑下,可能哪里会异常
为了配合create,并演示上面的过程,这个实现显得有些古怪,你习惯就好*/
void reverse(sqstack *s)
{
sqstack tmp; //你把盘子拿出来,总得有地方放,弄一个tmp栈来接纳他
create(&tmp);

/*反转的过程*/
while(s->top != s->bottom)
{
elemtype e;
pop(s, &e); //出栈,弹出元素暂时放到e
push(&tmp, e); //入栈,盘子从s拿出来,放到tmp,一次循环拿一个
//这里不用执行s->size --, tmp->size++ 因为在pop和push中做了
}
/*到这里,已经成功把元素搬到tmp了,,,
本来规范一点的做法是把新的栈返回给调用者,但是为了沿用你定义的接口
咱们偷梁换柱一下,把内存互换,内存就是容器,想象一下,两叠盘子底下都有个篮子用来装他们
假设篮子都贴着标签,第一个篮子签写着A, 搬动后放到篮子B上面,
问:你如何在不搬动盘子的情况下,让这叠盘子依然在篮子A里面呢(盘子都从A搬到B了)
聪明的你也许已经想到答案了,把篮子B的标签撕下来,然后把篮子A的标签贴到B上,
很流氓是不是?下面的代码就是这么干的 s->bottom就是这个所谓的标签
*/
elemtype *labtmp; //什么? 换个标签也这么麻烦?要找个地方现暂放一下,而不是把A直接贴到B上
labtmp = s->bottom; //想象一下,把A撕了,暂时贴到一块干净的玻璃上吧,免得把上面的胶水粘没了
s->bottom = tmp.bottom; //既然A撕掉了,B可以直接贴过来了,A篮子变成了标签B
tmp.bottom = labtmp; //原来的标签A贴过去,偷梁换柱完成。
s->top = tmp.top; //别忘记还有这个

/*至此完成反转 打印出来验证下看*/
//printf("after reverse:\n");
//printstack(s);

destroy(&tmp); //别忘了tmp只是暂时借来放东西的,把他释放掉吧,
/*再次强调,这并不是一个很好的实现,只是为了知识点简单一些,不引入更复杂的技巧的情况下的无奈之举*/
}

int main ()
{
sqstack s;
int e; //从数字几开始入栈
int count; //推几个数字入栈
char buf[256]; //存放用户输入

printf("enter the start num:\n");
fgets(buf, 256, stdin); //stdin 表示标准输入
e = atoi(buf); //字符串解释成整型
printf("enter the total count \n");
fgets(buf, 256, stdin);
count = atoi(buf);

if(create(&s) != 0){
return -1;
}

while(count > 0)
{
push(&s, e);
e++;
count--;
}

printf("origin stack :\n");
printstack(&s);

reverse(&s);

printf("after reverse:\n");
printstack(&s);

destroy(&s);
return 0;
}



附上我在linux环境下的编译运行过程



顺带说一下,你要注意提问题的方式,提问的时候,最好是源代码复制上来,而不是贴图
这样别人在阅读和修改你的代码都会很方便,千万千万别截图,这是尊重他人的体现。
想让人帮忙,但是截图简直是浪费别人时间。
感觉CSDN这个社区已经运营得烂掉了,没人在乎你是否截图提问,只知道骗人买会员,,

哇 早上醒来就看见这么多代码 还有讲解, 好感动 ,老哥 我是一名学生 前面根本不学习,现在后悔了想学了 就是看不懂了 哎 谢谢老哥 老哥我关注你一下吧 [/quote]
以后会附代码的,我也是不知道, c语言我真的是一知半解, 算得上是半路出家,难一点我就不会,尤其是指针,总是懵逼,但这东西也不能着急,就得慢慢消化,所以我现在很煎熬 害~[/quote]

对指针我有一种理解,可以参考:
指针就是int,只不过是特殊的int。特殊在它被明确指出其内容应是一个地址。

int a = 0;
void* p = &a; //就相当于有一个int p 存了a的地址。

指针的使用:
int x = *p//相当于把地址对应的位置开始取一个int(整数)出来。
然后就没了。理解一句话就足够了:指针就是int,只不过是特殊的int。特殊在它被明确指出其内容应是一个地址。
老拆 2020-03-20
  • 打赏
  • 举报
回复
引用 2 楼 m0_46472878的回复:
[quote=引用 1 楼 yukint的回复:]你的原意是想用数组还是链表实现一个栈呢?,看你的意思是想用数组, 我根据你写的写个给你吧 真的C语言对于没有一些计算机基础的人,特别难,你唯一能做的是练习练习 关键还看懂的人,能不能讲到你懂位置,自己还要去体悟,理解需要一个过程
#include <stdio.h>
#include <stdlib.h>
/*数组实现栈*/
#define MAXSIZE 256
/*程序命名风格,要么都用大写开头,命名类型和函数,要么都用小写
与厦门的sqstack, pop等保持一致,不要混用两种风格
*/
typedef  int elemtype;      
typedef struct list
{
    elemtype *bottom;   //命名规范,bottom 对top,,high对low,,
    elemtype *top; //既然想通过typedef 来方便修改类型就统一用这个,而不是int*
    int capability; //栈的总容量,不是栈中元素个数
}sqstack;

/*
1   变量命名用小写,不要大写
2   sqstack *s 用指针, 就已经表示传的是地址了, 指针变量是变量的一种
    都是这么定义的,而不是用&s
    调用的时候才用取地址符号
    比如 sqstack stack_test;
        init(&stack_test)
*/
/*考虑到栈有建立,就要有响应的销毁过程与之对应
以便释放内存,这里将init改成create,
同时新增destroy函数*/

/*
return: 0成功, 1 失败
不要对同一个s重复调用,否则会内存泄漏
*/
int create(sqstack *s)
{
    s->bottom = (elemtype *)malloc(MAXSIZE * sizeof(elemtype)); //*申请连续空间----,而不是申请一个
    if(!s->bottom){ //等价于 if(s->bottom == NULL)
        printf("malloc memory error\n");
        return 1;
    }
    s->top = s->bottom; //指针访问成员,用箭头->,而不是.
    s->capability = MAXSIZE;
    return 0;       //
}
/*要求使用者很小心,必须是成功create过的s,才能调用*/
void destroy(sqstack *s)
{
    if(s->bottom)   //bottom是不变的,用于记录申请的空间,
    {
        free(s->bottom);
        s->bottom = NULL;
    }
    return;
}

int push(sqstack *s, elemtype e)
{
    /*指针让人产生歧义的地方,有时候图方便,你会想当然的认为,要取栈顶元素,直接拿top就是了
	 * 事实上,要取栈顶元素的时候,是top-1,而不是top!!
	 * 既然top开始指向可放元素的地方,即入栈位置,那么他表示top入完栈之后,你把他加1, 显然top指示的是一个未知元素,,,
	 * 继续看后面的实现,就知道top指针多尴尬
    */
    if(s->top - s->bottom == s->capability)
    {
        //栈满了,扩容
        printf("stack full, realloc a larger space\n");
        elemtype *new_ptr = (elemtype *)realloc(s->bottom, s->capability * 2);
        if(new_ptr == NULL)//重新分配失败,原来的保留
        {
            printf("fail to realloc more memory\n");
            return 1;
        }
        s->bottom = new_ptr;
        s->capability = 2 * s->capability;
    }
    
    *s->top++ = e;
    return 0;
}

/*
return : 0 ok,  1 err 栈为空,无法再弹出(pop)元素出来
*/
int pop(sqstack *s, elemtype *e)
{
    if(s->top == s->bottom)
    {
        printf("stack is empty\n");
        return 1;
    }

    *e = *--s->top;
    return 0;
}
/*自顶向下打印栈*/
void printstack(sqstack *s)
{
    /*
    这里要减1,用简单情况进行推理
    比如栈只有1个元素的时候,这个元素就在第0个位置
    C语言连续内存,比如数组,总是从0开始
    */
    if(s->top == s->bottom) 
    {
        printf("stack is empty, nothing in it\n");
        return;
    } 

    printf("print stack s from top to bottom\n");
	elemtype *itor = s->top;	//因为只是打印,不要去改变这个栈,所以用临时变量来进行遍历
    while (itor != s->bottom)	//虽然是很不好的风格,,谁让你用指针呢, 而且指针绕到你头疼
    {
        /*这里假定elemtype 是int(用%d打印),这就是C语言麻烦的地方
        先不多扯了,想想如果是double,是不是要另外写函数,
        一般要用函数指针来实现,你先了解下就好*/

        /*%d 后面有空格,2d表示用两个位置来打印一个数,
        额额,如果3位数? 3d,如果不确定几位,那就不对齐了,,,
        这里只是在对比的时候能对齐,好看*/
        printf("%2d ", *--itor);	//如果用 *--s->top;,,那你一边打印,一遍出栈了。。。
    }
    printf("\n");   //换行
}
/*反转栈 
虽然这样写比较没效率,但是想象一下
你有一叠盘子,嗯,底下的盘子大,上面的盘子小
现在,你从顶部开始一个一个拿下来,一次叠到另外一个地方,想象一下
       -                  ----
       --     -->          ---
       ---                  --
       ----                  -
     
*/
/*略去了错误处理,你可以考虑下,可能哪里会异常
为了配合create,并演示上面的过程,这个实现显得有些古怪,你习惯就好*/
void reverse(sqstack *s)
{
    sqstack tmp;    //你把盘子拿出来,总得有地方放,弄一个tmp栈来接纳他
    create(&tmp);

    /*反转的过程*/
    while(s->top != s->bottom)
    {
        elemtype e;
        pop(s, &e); //出栈,弹出元素暂时放到e
        push(&tmp, e);  //入栈,盘子从s拿出来,放到tmp,一次循环拿一个
        //这里不用执行s->size --, tmp->size++ 因为在pop和push中做了
    }
    /*到这里,已经成功把元素搬到tmp了,,,
    本来规范一点的做法是把新的栈返回给调用者,但是为了沿用你定义的接口
    咱们偷梁换柱一下,把内存互换,内存就是容器,想象一下,两叠盘子底下都有个篮子用来装他们
    假设篮子都贴着标签,第一个篮子签写着A, 搬动后放到篮子B上面,
    问:你如何在不搬动盘子的情况下,让这叠盘子依然在篮子A里面呢(盘子都从A搬到B了)
    聪明的你也许已经想到答案了,把篮子B的标签撕下来,然后把篮子A的标签贴到B上,
    很流氓是不是?下面的代码就是这么干的 s->bottom就是这个所谓的标签
    */
    elemtype *labtmp;   //什么? 换个标签也这么麻烦?要找个地方现暂放一下,而不是把A直接贴到B上
    labtmp = s->bottom; //想象一下,把A撕了,暂时贴到一块干净的玻璃上吧,免得把上面的胶水粘没了
    s->bottom = tmp.bottom;  //既然A撕掉了,B可以直接贴过来了,A篮子变成了标签B
    tmp.bottom = labtmp;    //原来的标签A贴过去,偷梁换柱完成。
	s->top = tmp.top;	//别忘记还有这个

    /*至此完成反转 打印出来验证下看*/
    //printf("after reverse:\n");
    //printstack(s);

    destroy(&tmp);      //别忘了tmp只是暂时借来放东西的,把他释放掉吧,
    /*再次强调,这并不是一个很好的实现,只是为了知识点简单一些,不引入更复杂的技巧的情况下的无奈之举*/
}

int main ()
{
    sqstack s;
    int e;  //从数字几开始入栈
    int count;  //推几个数字入栈
    char buf[256];  //存放用户输入

    printf("enter the start num:\n");
    fgets(buf, 256, stdin);  //stdin 表示标准输入
    e = atoi(buf);		//字符串解释成整型
    printf("enter the total count \n");
    fgets(buf, 256, stdin);
    count = atoi(buf);

    if(create(&s) != 0){
        return -1;
    }

    while(count > 0)
    {
        push(&s, e);
        e++;
        count--;
    }

    printf("origin stack :\n");
    printstack(&s);

    reverse(&s);

    printf("after reverse:\n");
    printstack(&s);

    destroy(&s);
    return 0;
}
附上我在linux环境下的编译运行过程 顺带说一下,你要注意提问题的方式,提问的时候,最好是源代码复制上来,而不是贴图 这样别人在阅读和修改你的代码都会很方便,千万千万别截图,这是尊重他人的体现。 想让人帮忙,但是截图简直是浪费别人时间。 感觉CSDN这个社区已经运营得烂掉了,没人在乎你是否截图提问,只知道骗人买会员,,
哇 早上醒来就看见这么多代码 还有讲解, 好感动 ,老哥 我是一名学生 前面根本不学习,现在后悔了想学了 就是看不懂了 哎 谢谢老哥 老哥我关注你一下吧 [/quote] 以后会附代码的,我也是不知道😂, c语言我真的是一知半解, 算得上是半路出家,难一点我就不会,尤其是指针,总是懵逼,但这东西也不能着急,就得慢慢消化,所以我现在很煎熬 害~
老拆 2020-03-20
  • 打赏
  • 举报
回复
引用 1 楼 yukint的回复:
你的原意是想用数组还是链表实现一个栈呢?,看你的意思是想用数组, 我根据你写的写个给你吧 真的C语言对于没有一些计算机基础的人,特别难,你唯一能做的是练习练习 关键还看懂的人,能不能讲到你懂位置,自己还要去体悟,理解需要一个过程
#include <stdio.h>
#include <stdlib.h>
/*数组实现栈*/
#define MAXSIZE 256
/*程序命名风格,要么都用大写开头,命名类型和函数,要么都用小写
与厦门的sqstack, pop等保持一致,不要混用两种风格
*/
typedef  int elemtype;      
typedef struct list
{
    elemtype *bottom;   //命名规范,bottom 对top,,high对low,,
    elemtype *top; //既然想通过typedef 来方便修改类型就统一用这个,而不是int*
    int capability; //栈的总容量,不是栈中元素个数
}sqstack;

/*
1   变量命名用小写,不要大写
2   sqstack *s 用指针, 就已经表示传的是地址了, 指针变量是变量的一种
    都是这么定义的,而不是用&s
    调用的时候才用取地址符号
    比如 sqstack stack_test;
        init(&stack_test)
*/
/*考虑到栈有建立,就要有响应的销毁过程与之对应
以便释放内存,这里将init改成create,
同时新增destroy函数*/

/*
return: 0成功, 1 失败
不要对同一个s重复调用,否则会内存泄漏
*/
int create(sqstack *s)
{
    s->bottom = (elemtype *)malloc(MAXSIZE * sizeof(elemtype)); //*申请连续空间----,而不是申请一个
    if(!s->bottom){ //等价于 if(s->bottom == NULL)
        printf("malloc memory error\n");
        return 1;
    }
    s->top = s->bottom; //指针访问成员,用箭头->,而不是.
    s->capability = MAXSIZE;
    return 0;       //
}
/*要求使用者很小心,必须是成功create过的s,才能调用*/
void destroy(sqstack *s)
{
    if(s->bottom)   //bottom是不变的,用于记录申请的空间,
    {
        free(s->bottom);
        s->bottom = NULL;
    }
    return;
}

int push(sqstack *s, elemtype e)
{
    /*指针让人产生歧义的地方,有时候图方便,你会想当然的认为,要取栈顶元素,直接拿top就是了
	 * 事实上,要取栈顶元素的时候,是top-1,而不是top!!
	 * 既然top开始指向可放元素的地方,即入栈位置,那么他表示top入完栈之后,你把他加1, 显然top指示的是一个未知元素,,,
	 * 继续看后面的实现,就知道top指针多尴尬
    */
    if(s->top - s->bottom == s->capability)
    {
        //栈满了,扩容
        printf("stack full, realloc a larger space\n");
        elemtype *new_ptr = (elemtype *)realloc(s->bottom, s->capability * 2);
        if(new_ptr == NULL)//重新分配失败,原来的保留
        {
            printf("fail to realloc more memory\n");
            return 1;
        }
        s->bottom = new_ptr;
        s->capability = 2 * s->capability;
    }
    
    *s->top++ = e;
    return 0;
}

/*
return : 0 ok,  1 err 栈为空,无法再弹出(pop)元素出来
*/
int pop(sqstack *s, elemtype *e)
{
    if(s->top == s->bottom)
    {
        printf("stack is empty\n");
        return 1;
    }

    *e = *--s->top;
    return 0;
}
/*自顶向下打印栈*/
void printstack(sqstack *s)
{
    /*
    这里要减1,用简单情况进行推理
    比如栈只有1个元素的时候,这个元素就在第0个位置
    C语言连续内存,比如数组,总是从0开始
    */
    if(s->top == s->bottom) 
    {
        printf("stack is empty, nothing in it\n");
        return;
    } 

    printf("print stack s from top to bottom\n");
	elemtype *itor = s->top;	//因为只是打印,不要去改变这个栈,所以用临时变量来进行遍历
    while (itor != s->bottom)	//虽然是很不好的风格,,谁让你用指针呢, 而且指针绕到你头疼
    {
        /*这里假定elemtype 是int(用%d打印),这就是C语言麻烦的地方
        先不多扯了,想想如果是double,是不是要另外写函数,
        一般要用函数指针来实现,你先了解下就好*/

        /*%d 后面有空格,2d表示用两个位置来打印一个数,
        额额,如果3位数? 3d,如果不确定几位,那就不对齐了,,,
        这里只是在对比的时候能对齐,好看*/
        printf("%2d ", *--itor);	//如果用 *--s->top;,,那你一边打印,一遍出栈了。。。
    }
    printf("\n");   //换行
}
/*反转栈 
虽然这样写比较没效率,但是想象一下
你有一叠盘子,嗯,底下的盘子大,上面的盘子小
现在,你从顶部开始一个一个拿下来,一次叠到另外一个地方,想象一下
       -                  ----
       --     -->          ---
       ---                  --
       ----                  -
     
*/
/*略去了错误处理,你可以考虑下,可能哪里会异常
为了配合create,并演示上面的过程,这个实现显得有些古怪,你习惯就好*/
void reverse(sqstack *s)
{
    sqstack tmp;    //你把盘子拿出来,总得有地方放,弄一个tmp栈来接纳他
    create(&tmp);

    /*反转的过程*/
    while(s->top != s->bottom)
    {
        elemtype e;
        pop(s, &e); //出栈,弹出元素暂时放到e
        push(&tmp, e);  //入栈,盘子从s拿出来,放到tmp,一次循环拿一个
        //这里不用执行s->size --, tmp->size++ 因为在pop和push中做了
    }
    /*到这里,已经成功把元素搬到tmp了,,,
    本来规范一点的做法是把新的栈返回给调用者,但是为了沿用你定义的接口
    咱们偷梁换柱一下,把内存互换,内存就是容器,想象一下,两叠盘子底下都有个篮子用来装他们
    假设篮子都贴着标签,第一个篮子签写着A, 搬动后放到篮子B上面,
    问:你如何在不搬动盘子的情况下,让这叠盘子依然在篮子A里面呢(盘子都从A搬到B了)
    聪明的你也许已经想到答案了,把篮子B的标签撕下来,然后把篮子A的标签贴到B上,
    很流氓是不是?下面的代码就是这么干的 s->bottom就是这个所谓的标签
    */
    elemtype *labtmp;   //什么? 换个标签也这么麻烦?要找个地方现暂放一下,而不是把A直接贴到B上
    labtmp = s->bottom; //想象一下,把A撕了,暂时贴到一块干净的玻璃上吧,免得把上面的胶水粘没了
    s->bottom = tmp.bottom;  //既然A撕掉了,B可以直接贴过来了,A篮子变成了标签B
    tmp.bottom = labtmp;    //原来的标签A贴过去,偷梁换柱完成。
	s->top = tmp.top;	//别忘记还有这个

    /*至此完成反转 打印出来验证下看*/
    //printf("after reverse:\n");
    //printstack(s);

    destroy(&tmp);      //别忘了tmp只是暂时借来放东西的,把他释放掉吧,
    /*再次强调,这并不是一个很好的实现,只是为了知识点简单一些,不引入更复杂的技巧的情况下的无奈之举*/
}

int main ()
{
    sqstack s;
    int e;  //从数字几开始入栈
    int count;  //推几个数字入栈
    char buf[256];  //存放用户输入

    printf("enter the start num:\n");
    fgets(buf, 256, stdin);  //stdin 表示标准输入
    e = atoi(buf);		//字符串解释成整型
    printf("enter the total count \n");
    fgets(buf, 256, stdin);
    count = atoi(buf);

    if(create(&s) != 0){
        return -1;
    }

    while(count > 0)
    {
        push(&s, e);
        e++;
        count--;
    }

    printf("origin stack :\n");
    printstack(&s);

    reverse(&s);

    printf("after reverse:\n");
    printstack(&s);

    destroy(&s);
    return 0;
}
附上我在linux环境下的编译运行过程 顺带说一下,你要注意提问题的方式,提问的时候,最好是源代码复制上来,而不是贴图 这样别人在阅读和修改你的代码都会很方便,千万千万别截图,这是尊重他人的体现。 想让人帮忙,但是截图简直是浪费别人时间。 感觉CSDN这个社区已经运营得烂掉了,没人在乎你是否截图提问,只知道骗人买会员,,
哇 早上醒来就看见这么多代码 还有讲解, 好感动 ,老哥 我是一名学生 前面根本不学习,现在后悔了想学了 就是看不懂了 哎 谢谢老哥 老哥我关注你一下吧
yukint 2020-03-20
  • 打赏
  • 举报
回复
你的原意是想用数组还是链表实现一个栈呢?,看你的意思是想用数组, 我根据你写的写个给你吧 真的C语言对于没有一些计算机基础的人,特别难,你唯一能做的是练习练习 关键还看懂的人,能不能讲到你懂位置,自己还要去体悟,理解需要一个过程
#include <stdio.h>
#include <stdlib.h>
/*数组实现栈*/
#define MAXSIZE 256
/*程序命名风格,要么都用大写开头,命名类型和函数,要么都用小写
与厦门的sqstack, pop等保持一致,不要混用两种风格
*/
typedef  int elemtype;      
typedef struct list
{
    elemtype *bottom;   //命名规范,bottom 对top,,high对low,,
    elemtype *top; //既然想通过typedef 来方便修改类型就统一用这个,而不是int*
    int capability; //栈的总容量,不是栈中元素个数
}sqstack;

/*
1   变量命名用小写,不要大写
2   sqstack *s 用指针, 就已经表示传的是地址了, 指针变量是变量的一种
    都是这么定义的,而不是用&s
    调用的时候才用取地址符号
    比如 sqstack stack_test;
        init(&stack_test)
*/
/*考虑到栈有建立,就要有响应的销毁过程与之对应
以便释放内存,这里将init改成create,
同时新增destroy函数*/

/*
return: 0成功, 1 失败
不要对同一个s重复调用,否则会内存泄漏
*/
int create(sqstack *s)
{
    s->bottom = (elemtype *)malloc(MAXSIZE * sizeof(elemtype)); //*申请连续空间----,而不是申请一个
    if(!s->bottom){ //等价于 if(s->bottom == NULL)
        printf("malloc memory error\n");
        return 1;
    }
    s->top = s->bottom; //指针访问成员,用箭头->,而不是.
    s->capability = MAXSIZE;
    return 0;       //
}
/*要求使用者很小心,必须是成功create过的s,才能调用*/
void destroy(sqstack *s)
{
    if(s->bottom)   //bottom是不变的,用于记录申请的空间,
    {
        free(s->bottom);
        s->bottom = NULL;
    }
    return;
}

int push(sqstack *s, elemtype e)
{
    /*指针让人产生歧义的地方,有时候图方便,你会想当然的认为,要取栈顶元素,直接拿top就是了
	 * 事实上,要取栈顶元素的时候,是top-1,而不是top!!
	 * 既然top开始指向可放元素的地方,即入栈位置,那么他表示top入完栈之后,你把他加1, 显然top指示的是一个未知元素,,,
	 * 继续看后面的实现,就知道top指针多尴尬
    */
    if(s->top - s->bottom == s->capability)
    {
        //栈满了,扩容
        printf("stack full, realloc a larger space\n");
        elemtype *new_ptr = (elemtype *)realloc(s->bottom, s->capability * 2);
        if(new_ptr == NULL)//重新分配失败,原来的保留
        {
            printf("fail to realloc more memory\n");
            return 1;
        }
        s->bottom = new_ptr;
        s->capability = 2 * s->capability;
    }
    
    *s->top++ = e;
    return 0;
}

/*
return : 0 ok,  1 err 栈为空,无法再弹出(pop)元素出来
*/
int pop(sqstack *s, elemtype *e)
{
    if(s->top == s->bottom)
    {
        printf("stack is empty\n");
        return 1;
    }

    *e = *--s->top;
    return 0;
}
/*自顶向下打印栈*/
void printstack(sqstack *s)
{
    /*
    这里要减1,用简单情况进行推理
    比如栈只有1个元素的时候,这个元素就在第0个位置
    C语言连续内存,比如数组,总是从0开始
    */
    if(s->top == s->bottom) 
    {
        printf("stack is empty, nothing in it\n");
        return;
    } 

    printf("print stack s from top to bottom\n");
	elemtype *itor = s->top;	//因为只是打印,不要去改变这个栈,所以用临时变量来进行遍历
    while (itor != s->bottom)	//虽然是很不好的风格,,谁让你用指针呢, 而且指针绕到你头疼
    {
        /*这里假定elemtype 是int(用%d打印),这就是C语言麻烦的地方
        先不多扯了,想想如果是double,是不是要另外写函数,
        一般要用函数指针来实现,你先了解下就好*/

        /*%d 后面有空格,2d表示用两个位置来打印一个数,
        额额,如果3位数? 3d,如果不确定几位,那就不对齐了,,,
        这里只是在对比的时候能对齐,好看*/
        printf("%2d ", *--itor);	//如果用 *--s->top;,,那你一边打印,一遍出栈了。。。
    }
    printf("\n");   //换行
}
/*反转栈 
虽然这样写比较没效率,但是想象一下
你有一叠盘子,嗯,底下的盘子大,上面的盘子小
现在,你从顶部开始一个一个拿下来,一次叠到另外一个地方,想象一下
       -                  ----
       --     -->          ---
       ---                  --
       ----                  -
     
*/
/*略去了错误处理,你可以考虑下,可能哪里会异常
为了配合create,并演示上面的过程,这个实现显得有些古怪,你习惯就好*/
void reverse(sqstack *s)
{
    sqstack tmp;    //你把盘子拿出来,总得有地方放,弄一个tmp栈来接纳他
    create(&tmp);

    /*反转的过程*/
    while(s->top != s->bottom)
    {
        elemtype e;
        pop(s, &e); //出栈,弹出元素暂时放到e
        push(&tmp, e);  //入栈,盘子从s拿出来,放到tmp,一次循环拿一个
        //这里不用执行s->size --, tmp->size++ 因为在pop和push中做了
    }
    /*到这里,已经成功把元素搬到tmp了,,,
    本来规范一点的做法是把新的栈返回给调用者,但是为了沿用你定义的接口
    咱们偷梁换柱一下,把内存互换,内存就是容器,想象一下,两叠盘子底下都有个篮子用来装他们
    假设篮子都贴着标签,第一个篮子签写着A, 搬动后放到篮子B上面,
    问:你如何在不搬动盘子的情况下,让这叠盘子依然在篮子A里面呢(盘子都从A搬到B了)
    聪明的你也许已经想到答案了,把篮子B的标签撕下来,然后把篮子A的标签贴到B上,
    很流氓是不是?下面的代码就是这么干的 s->bottom就是这个所谓的标签
    */
    elemtype *labtmp;   //什么? 换个标签也这么麻烦?要找个地方现暂放一下,而不是把A直接贴到B上
    labtmp = s->bottom; //想象一下,把A撕了,暂时贴到一块干净的玻璃上吧,免得把上面的胶水粘没了
    s->bottom = tmp.bottom;  //既然A撕掉了,B可以直接贴过来了,A篮子变成了标签B
    tmp.bottom = labtmp;    //原来的标签A贴过去,偷梁换柱完成。
	s->top = tmp.top;	//别忘记还有这个

    /*至此完成反转 打印出来验证下看*/
    //printf("after reverse:\n");
    //printstack(s);

    destroy(&tmp);      //别忘了tmp只是暂时借来放东西的,把他释放掉吧,
    /*再次强调,这并不是一个很好的实现,只是为了知识点简单一些,不引入更复杂的技巧的情况下的无奈之举*/
}

int main ()
{
    sqstack s;
    int e;  //从数字几开始入栈
    int count;  //推几个数字入栈
    char buf[256];  //存放用户输入

    printf("enter the start num:\n");
    fgets(buf, 256, stdin);  //stdin 表示标准输入
    e = atoi(buf);		//字符串解释成整型
    printf("enter the total count \n");
    fgets(buf, 256, stdin);
    count = atoi(buf);

    if(create(&s) != 0){
        return -1;
    }

    while(count > 0)
    {
        push(&s, e);
        e++;
        count--;
    }

    printf("origin stack :\n");
    printstack(&s);

    reverse(&s);

    printf("after reverse:\n");
    printstack(&s);

    destroy(&s);
    return 0;
}
附上我在linux环境下的编译运行过程 顺带说一下,你要注意提问题的方式,提问的时候,最好是源代码复制上来,而不是贴图 这样别人在阅读和修改你的代码都会很方便,千万千万别截图,这是尊重他人的体现。 想让人帮忙,但是截图简直是浪费别人时间。 感觉CSDN这个社区已经运营得烂掉了,没人在乎你是否截图提问,只知道骗人买会员,,

69,374

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧