奥普瓯江 发表于 2021-10-27 17:50:52

栈、二进制转10进制为什么一到malloc就执行不下去了?

错误点:执行到InitStack含税里的malloc就崩溃

代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define MAXSIZE 100

typedef int Elemtype;

//建立类
typedef struct
{
    Elemtype *base;   //尾指针
    Elemtype *top;      //头指针
    int StackSize;      //剩余空间
}SqStack;

void InitStack(SqStack **E);      //初始化创建空栈
void PopStack(SqStack **E, Elemtype N);          //进栈
void PushStack(SqStack *E);         //出栈

void PushStack(SqStack *E)         //出栈
{
    E->top--;
    E->StackSize++;
}

void PopStack(SqStack **E, Elemtype N)          //进栈
{
    if((*E)->top - (*E)->base >= (*E)->StackSize)
    {
      (*E)->base = (Elemtype *)realloc((*E)->base, ((*E)->StackSize + MAXSIZE) * sizeof(Elemtype ));      //复制前面的base中的数据进入到扩大后的base中
      if(!(*E)->base)
      {
            printf("内存分配失败本程序结束运行\n");          //判断是内存地址是否分配成功
            exit(0);
      }
      (*E)->top = (*E)->base + (*E)->StackSize;         //因为以是新的内存空间所有,top中标记的地址也是错误的,所以按照以占用多少空间从新赋予top地址(realloc已经把数据复制过来了)
      (*E)->StackSize = (*E)->StackSize + MAXSIZE;      //从新赋予记述节点数据
    }
    *((*E)->top) = N;
    (*E)->top++;
    (*E)->StackSize--;

}
void InitStack(SqStack **E)      //初始化创建空栈
{
   (*E)->base = (Elemtype *)malloc(MAXSIZE * sizeof(Elemtype ));   //向指针类中的base赋予空间

    if(!(*E)->base)
    {
      printf("内存分配失败本程序结束运行\n");          //判断是内存地址是否分配成功
      exit(0);
    }
    (*E)->top = (*E)->base;         //把初始地址传给头指针
    (*E)->StackSize = MAXSIZE;      //初始剩余空间数量
}

int main()
{
    SqStack *T = NULL;
    char litte;
    int F, N;

    InitStack(&T);

    //把ASCII传给字符串
    scanf("%s", litte);

    for(int i = 0; litte != 0; i++ )
    {
      litte = litte - 48;
      PopStack(&T,litte);
    }

    for(int i = 0; T->top != T->base; i++)
    {
      PushStack(T);
      F = *(T->top) * pow(i, 2);
      N += F;
    }

    printf("%d", N);


    return 0;
}

人造人 发表于 2021-10-27 19:15:58

错的地方有点多呀

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdbool.h>

#define MAXSIZE 100

typedef int Elemtype;

//建立类
typedef struct {
    Elemtype *base; //尾指针
    Elemtype *top;//头指针
    int StackSize;//剩余空间
} SqStack;

/*
void InitStack(SqStack **E);            //初始化创建空栈
void PopStack(SqStack **E, Elemtype N); //进栈// pop 是进栈?
void PushStack(SqStack *E);             //出栈// 同样
*/

//void PushStack(SqStack *E) //出栈
void PopStack(SqStack *E) //出栈
{
    E->top--;
    //E->StackSize++;
}

//void PopStack(SqStack **E, Elemtype N) //进栈
void PushStack(SqStack **E, Elemtype N) //进栈
{
    if((*E)->top - (*E)->base >= (*E)->StackSize) {
      (*E)->StackSize += MAXSIZE;
      //(*E)->base = (Elemtype *)realloc((*E)->base, ((*E)->StackSize + MAXSIZE) *
      (*E)->base = (Elemtype *)realloc((*E)->base, (*E)->StackSize *
                sizeof(Elemtype)); //复制前面的base中的数据进入到扩大后的base中
      if(!(*E)->base) {
            printf("内存分配失败本程序结束运行\n"); //判断是内存地址是否分配成功
            exit(0);
      }
      (*E)->top =
            (*E)->base +
            (*E)->StackSize - MAXSIZE; //因为以是新的内存空间所有,top中标记的地址也是错误的,所以按照以占用多少空间从新赋予top地址(realloc已经把数据复制过来了)
      //(*E)->StackSize = (*E)->StackSize + MAXSIZE; //从新赋予记述节点数据
    }
    *((*E)->top) = N;
    (*E)->top++;
    //(*E)->StackSize--;
}

Elemtype stack_top(SqStack *s) {
    return *(s->top - 1);
}

bool stack_empty(SqStack *s) {
    return s->base == s->top;
}

void InitStack(SqStack **E) //初始化创建空栈
{
    *E = malloc(sizeof(**E));
    (*E)->base = (Elemtype *)malloc(MAXSIZE * sizeof(Elemtype)); //向指针类中的base赋予空间

    if(!(*E)->base) {
      printf("内存分配失败本程序结束运行\n"); //判断是内存地址是否分配成功
      exit(0);
    }
    (*E)->top = (*E)->base;    //把初始地址传给头指针
    (*E)->StackSize = MAXSIZE; //初始剩余空间数量
}

// 为什么不写释放函数?
void stack_deinit(SqStack *s) {
    free(s->base); free(s);
}

int main() {
    SqStack *T = NULL;
    char litte;
    //int F, N;
    int N = 0;

    InitStack(&T);

    //把ASCII传给字符串
    scanf("%s", litte);

    //for(int i = 0; litte != 0; i++) {
    for(int i = 0; litte != '\0'; i++) {
      litte = litte - 48;
      PushStack(&T, litte);
    }

    /*
    for(int i = 0; T->top != T->base; i++) {
      PopStack(T);
      F = *(T->top) * pow(i, 2);
      N += F;
    }
    */
    for(size_t i = 0; !stack_empty(T); ++i) {
      N += stack_top(T) * pow(2, i);
      PopStack(T);
    }

    //printf("%d", N);
    printf("%d\n", N);

    stack_deinit(T);
    return 0;
}

奥普瓯江 发表于 2021-10-28 13:38:50

人造人 发表于 2021-10-27 19:15
错的地方有点多呀

这次第一个函数就没有执行下去,一个malloc就难道我了谢谢啊,以后注意改正,还有那个释放函数那个是我的不好习惯也一并改正,以后记得释放谢谢

奥普瓯江 发表于 2021-10-28 16:49:43

本帖最后由 奥普瓯江 于 2021-10-28 16:51 编辑

人造人 发表于 2021-10-27 19:15
错的地方有点多呀

我按照你那个代码给我自己写的这个改了以下,没有用你那两个函数stack_top、Elemtype stack_top我感觉(自己感觉啊)我这么写不应该是更明了容易读么?还请予以指点谢谢啊。

代码:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define MAXSIZE 100

typedef int Elemtype;

//建立类
typedef struct
{
    Elemtype *base;   //尾指针
    Elemtype *top;      //头指针
    int StackSize;      //剩余空间
}SqStack;

void InitStack(SqStack **E);      //初始化创建空栈
void PushStack(SqStack **E, Elemtype N);          //进栈
void PopStack(SqStack *E);          //出栈
void DeStack(SqStack **E);          //释放内存

void DeStack(SqStack **E)          //释放内存
{
    Elemtype *temp;

    for(int i = 0; i <= ((*E)->StackSize); i++)
    {
      temp = (*E)->base;
      (*E)->base++;
      free(temp);
    }
    free(*E);

}


void PopStack(SqStack *E)         //出栈
{
    E->top--;
    E->StackSize++;
}

void PushStack(SqStack **E, Elemtype N)          //进栈
{
    if((*E)->top - (*E)->base >= (*E)->StackSize)
    {
      (*E)->base = (Elemtype *)realloc((*E)->base, ((*E)->StackSize + MAXSIZE) * sizeof(Elemtype ));      //复制前面的base中的数据进入到扩大后的base中
      if(!(*E)->base)
      {
            printf("内存分配失败本程序结束运行\n");          //判断是内存地址是否分配成功
            exit(0);
      }
      (*E)->top = (*E)->base + (*E)->StackSize;         //因为以是新的内存空间所有,top中标记的地址也是错误的,所以按照以占用多少空间从新赋予top地址(realloc已经把数据复制过来了)
      (*E)->StackSize = (*E)->StackSize + MAXSIZE;      //从新赋予记述节点数据
    }
    *((*E)->top) = N;
    (*E)->top++;
    (*E)->StackSize--;

}
void InitStack(SqStack **E)      //初始化创建空栈
{
   (*E)->base = (Elemtype *)malloc(MAXSIZE * sizeof(Elemtype ));   //向指针类中的base赋予空间

    if(!(*E)->base)
    {
      printf("内存分配失败本程序结束运行\n");          //判断是内存地址是否分配成功
      exit(0);
    }
    (*E)->top = (*E)->base;         //把初始地址传给头指针
    (*E)->StackSize = MAXSIZE;      //初始剩余空间数量
}

int main()
{
    SqStack *T = (SqStack *)malloc(sizeof(SqStack ));
    char litte;
    int F = 0, N = 0;

    InitStack(&T);

    //把ASCII传给字符串
    scanf("%s", litte);

    for(int i = 0; litte != 0; i++ )
    {
      litte = litte - 48;
      PushStack(&T,litte);
    }

    for(int i = 0;T->top != T->base; i++)
    {
      PopStack(T);
      F = *(T->top) * pow(2, i);
      N += F;
    }

    printf("%d\n", N);

    DeStack(&T);
    return 0;
}

人造人 发表于 2021-10-28 17:26:11

奥普瓯江 发表于 2021-10-28 16:49
我按照你那个代码给我自己写的这个改了以下,没有用你那两个函数stack_top、Elemtype stack_top我感觉 ...

1. 不要直接操作数据结构的内部数据,要用专门的函数来操作
在这里你选择不用 stack_top、stack_empty
为什么不把 InitStack、PushStack、PopStack、DeStack
这些函数全部删除,直接把这些函数中的代码复制到 main 函数?
你选择复制 stack_top、stack_empty 这两个函数的代码到 main 函数,为什么 InitStack、PushStack、PopStack、DeStack 这些函数不复制?
什么是模块化编程?模块化编程的好处是什么?

2. 报错信息很明显 attempting free on address which was not malloc()-ed

$ gcc-debug -o main main.c -lm
$ ./main
10110101
181
=================================================================
==286537==ERROR: AddressSanitizer: attempting free on address which was not malloc()-ed: 0x614000000044 in thread T0
    #0 0x7fda7c3d4f19 in __interceptor_free /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cpp:127
    #1 0x55b613be5450 in DeStack /tmp/main.c:29
    #2 0x55b613be6e20 in main /tmp/main.c:99
    #3 0x7fda7b6c3b24 in __libc_start_main (/usr/lib/libc.so.6+0x27b24)
    #4 0x55b613be51fd in _start (/tmp/main+0x41fd)

0x614000000044 is located 4 bytes inside of 400-byte region [0x614000000040,0x6140000001d0)
freed by thread T0 here:
    #0 0x7fda7c3d4f19 in __interceptor_free /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cpp:127
    #1 0x55b613be5450 in DeStack /tmp/main.c:29
    #2 0x55b613be6e20 in main /tmp/main.c:99
    #3 0x7fda7b6c3b24 in __libc_start_main (/usr/lib/libc.so.6+0x27b24)

previously allocated by thread T0 here:
    #0 0x7fda7c3d5279 in __interceptor_malloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cpp:145
    #1 0x55b613be6366 in InitStack /tmp/main.c:62
    #2 0x55b613be6726 in main /tmp/main.c:79
    #3 0x7fda7b6c3b24 in __libc_start_main (/usr/lib/libc.so.6+0x27b24)

SUMMARY: AddressSanitizer: bad-free /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cpp:127 in __interceptor_free
==286537==ABORTING
$

3. 代码中尽量不要出现 神奇数字
litte = litte - 48;
48 是什么?
看起来是是一个 用于表示 ascii 的数字,具体表示的哪个字母?不知道,我得去查一查 ascii 表

写成这样呢?
litte = litte - '0';

人造人 发表于 2021-10-28 17:44:41

你在调用 printf 函数的时候是不是不关心也不知道这个函数是如何把字符串输出到屏幕上面的?
如果你在使用 printf 之前必须弄清楚 printf 内部的实现原理,然后才能使用 printf 函数,那你会选择使用这个函数吗?

你在使用 stack 的时候是不是不想关心也不想知道 stack 内部是如何实现的?
你在使用 stack 的时候是不是要先看一遍 stack 的源代码,弄清楚了 stack 内部的实现原理,然后才使用 stack,你会选择这样做吗?

如果 直接调用 stack 提供的函数呢?
要当前栈的栈顶,我直接调用 stack_top 函数就好,我为什么要去看一遍 stack 的代码,然后发现栈顶是 T->base,然后我在我的代码中使用这个
问题是,如果下一个版本,stack 的作者因为某些条件的限制(经费问题,硬件环境问题,代码重构,。。。),改变了内部数据结构,不在使用 T->base 怎么办?把你所有使用 T->base 的地方都改一遍?前提是先看一遍 stack 的源代码,找到原作者现在是使用什么作为栈顶的?如果原作者是调用了一系列函数来得到栈顶,你是不是要在你的代码中重写一遍这些函数?还是直接调用这些函数?
然后在下一版本,原作者又改了代码,得到栈顶不在使用之前的那一系列函数,你又得改你的代码,先看一遍 stack 的源代码,然后找到栈顶

问题是你直接调用 stack 提供的 stack_top 就可以得到栈顶,不管内部数据如何改变,这个函数的功能不会变,就是得到栈顶,无论内部数据如何变,调用这个函数都可以得到 栈顶

自己百度 模块化编程的好处

奥普瓯江 发表于 2021-10-28 17:52:59

人造人 发表于 2021-10-28 17:44
你在调用 printf 函数的时候是不是不关心也不知道这个函数是如何把字符串输出到屏幕上面的?
如果你在使用 ...

收到,谢谢,啊
后期我会找这方面的知识好好看看谢谢了

人造人 发表于 2021-10-28 17:55:08

奥普瓯江 发表于 2021-10-28 17:52
收到,谢谢,啊
后期我会找这方面的知识好好看看谢谢了

问题3 以后注意就好了
先改问题2 吧
问题2 哪里不会了再问

奥普瓯江 发表于 2021-10-29 10:46:39

人造人 发表于 2021-10-28 17:55
问题3 以后注意就好了
先改问题2 吧
问题2 哪里不会了再问

收到谢谢

奥普瓯江 发表于 2021-10-30 16:35:44

本帖最后由 奥普瓯江 于 2021-10-30 16:47 编辑

人造人 发表于 2021-10-28 17:26


还是得问一个问题,就是关于free或者椒malloc的问题,因为我发现我这个程序free释放的时候会出错我用CodeBlocks执行和vs6.0都会报错,我感觉应该还是你说的第2点哪里的错误,但是我没理解所以还的请教你一下,谢谢啊 ,有点笨{:10_266:}

void DeStack(SqStack **E)这个函数第一个free((*E)->top)这里出现的错误


#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdbool.h>
#define MAXSIZE 20

typedef int Elemtype;

//建立类
typedef struct
{
    Elemtype *base;   //尾指针
    Elemtype *top;      //头指针
    int StackSize;      //剩余空间
}SqStack;

void InitStack(SqStack **E);      //初始化创建空栈
void PushStack(SqStack **E, Elemtype N);          //进栈
Elemtype PopStack(SqStack *E);          //出栈
void DeStack(SqStack **E);          //释放内存
bool StackEmpty(SqStack *E);      //判断真假

bool StackEmpty(SqStack *E)      //判断真假
{
    return E->top == E->base;
}

void DeStack(SqStack **E)          //释放内存
{
    while(0 < (*E)->StackSize)
    {
      (*E)->base++;
      (*E)->StackSize--;
      free((*E)->top);
      (*E)->top = (*E)->base;
    }
    free(*E);
}

/*void DeStack(SqStack **E)          //释放内存
{
    Elemtype *temp;

    for(int i = 0; i < ((*E)->StackSize); i++)
    {
      temp = (*E)->base;
      (*E)->base++;
      free(temp);
    }
    free(*E);
}*/

Elemtype PopStack(SqStack *E)         //出栈
{
    E->top--;
    E->StackSize++;
    return *(E->top);
}

void PushStack(SqStack **E, Elemtype N)          //进栈
{
    if((*E)->top - (*E)->base >= (*E)->StackSize)
    {
      (*E)->base = (Elemtype *)realloc((*E)->base, ((*E)->StackSize + MAXSIZE) * sizeof(Elemtype ));      //复制前面的base中的数据进入到扩大后的base中
      if(!(*E)->base)
      {
            printf("内存分配失败本程序结束运行\n");          //判断是内存地址是否分配成功
            exit(0);
      }
      (*E)->top = (*E)->base + (*E)->StackSize;         //因为以是新的内存空间所有,top中标记的地址也是错误的,所以按照以占用多少空间从新赋予top地址(realloc已经把数据复制过来了)
      (*E)->StackSize = (*E)->StackSize + MAXSIZE;      //从新赋予记述节点数据
    }
    *((*E)->top) = N;
    (*E)->top++;
    (*E)->StackSize--;

}
void InitStack(SqStack **E)      //初始化创建空栈
{
    *E = (SqStack *)malloc(sizeof(SqStack ));
   (*E)->base = (Elemtype *)malloc(MAXSIZE * sizeof(Elemtype ));   //向指针类中的base赋予空间

    if(!(*E)->base)
    {
      printf("内存分配失败本程序结束运行\n");          //判断是内存地址是否分配成功
      exit(0);
    }
    (*E)->top = (*E)->base;         //把初始地址传给头指针
    (*E)->StackSize = MAXSIZE;      //初始剩余空间数量
}
int main()
{
    SqStack *T, *F;

    char litte;
    Elemtype N = 0;

    InitStack(&T);
    InitStack(&F);

    //把ASCII传给字符串
    scanf("%s", litte);

    for(int i = 0; litte != 0; i++ )
    {
      litte = litte - '0';
      PushStack(&T,litte);
    }

    //转十六进制
    while(!StackEmpty(T))
    {
       for(int i = 0; i < 4 && !StackEmpty(T); i++)
       {
         N += PopStack(T) * pow(2, i);      //倒着出栈运算
       }
       PushStack(&F,N);                         //在进栈
       N = 0;
    }
    while(F->top != F->base)
    {
      printf("%x", PopStack(F));            //打印栈中的每一个数据
    }

    DeStack(&T);
    DeStack(&F);
    return 0;
}

人造人 发表于 2021-10-30 17:11:09

很简单,你 malloc 得到的那个地址给了谁,之后就 free 谁
执行了多少次 malloc 就执行多少次 free

*E = (SqStack *)malloc(sizeof(SqStack ));
(*E)->base = (Elemtype *)malloc(MAXSIZE * sizeof(Elemtype ));
// ...
free((*E)->base);
free(*E);


#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdbool.h>
#define MAXSIZE 20

typedef int Elemtype;

//建立类
typedef struct
{
    Elemtype *base;   //尾指针
    Elemtype *top;      //头指针
    int StackSize;      //剩余空间
}SqStack;

void InitStack(SqStack **E);      //初始化创建空栈
void PushStack(SqStack **E, Elemtype N);          //进栈
Elemtype PopStack(SqStack *E);          //出栈
void DeStack(SqStack **E);          //释放内存
bool StackEmpty(SqStack *E);      //判断真假

bool StackEmpty(SqStack *E)      //判断真假
{
    return E->top == E->base;
}

void DeStack(SqStack **E)          //释放内存
{
    free((*E)->base); free(*E);
    /*
    while(0 < (*E)->StackSize)
    {
      (*E)->base++;
      (*E)->StackSize--;
      free((*E)->top);
      (*E)->top = (*E)->base;
    }
    free(*E);
    */
}

/*void DeStack(SqStack **E)          //释放内存
{
    Elemtype *temp;

    for(int i = 0; i < ((*E)->StackSize); i++)
    {
      temp = (*E)->base;
      (*E)->base++;
      free(temp);
    }
    free(*E);
}*/

Elemtype PopStack(SqStack *E)         //出栈
{
    E->top--;
    E->StackSize++;
    return *(E->top);
}

void PushStack(SqStack **E, Elemtype N)          //进栈
{
    if((*E)->top - (*E)->base >= (*E)->StackSize)
    {
      (*E)->base = (Elemtype *)realloc((*E)->base, ((*E)->StackSize + MAXSIZE) * sizeof(Elemtype ));      //复制前面的base中的数据进入到扩大后的base中
      if(!(*E)->base)
      {
            printf("内存分配失败本程序结束运行\n");          //判断是内存地址是否分配成功
            exit(0);
      }
      (*E)->top = (*E)->base + (*E)->StackSize;         //因为以是新的内存空间所有,top中标记的地址也是错误的,所以按照以占用多少空间从新赋予top地址(realloc已经把数据复制过来了)
      (*E)->StackSize = (*E)->StackSize + MAXSIZE;      //从新赋予记述节点数据
    }
    *((*E)->top) = N;
    (*E)->top++;
    (*E)->StackSize--;

}
void InitStack(SqStack **E)      //初始化创建空栈
{
    *E = (SqStack *)malloc(sizeof(SqStack ));
   (*E)->base = (Elemtype *)malloc(MAXSIZE * sizeof(Elemtype ));   //向指针类中的base赋予空间

    if(!(*E)->base)
    {
      printf("内存分配失败本程序结束运行\n");          //判断是内存地址是否分配成功
      exit(0);
    }
    (*E)->top = (*E)->base;         //把初始地址传给头指针
    (*E)->StackSize = MAXSIZE;      //初始剩余空间数量
}
int main()
{
    SqStack *T, *F;

    char litte;
    Elemtype N = 0;

    InitStack(&T);
    InitStack(&F);

    //把ASCII传给字符串
    scanf("%s", litte);

    for(int i = 0; litte != 0; i++ )
    {
      litte = litte - '0';
      PushStack(&T,litte);
    }

    //转十六进制
    while(!StackEmpty(T))
    {
       for(int i = 0; i < 4 && !StackEmpty(T); i++)
       {
         N += PopStack(T) * pow(2, i);      //倒着出栈运算
       }
       PushStack(&F,N);                         //在进栈
       N = 0;
    }
    while(F->top != F->base)
    {
      printf("%x", PopStack(F));            //打印栈中的每一个数据
    }
    printf("\n");

    DeStack(&T);
    DeStack(&F);
    return 0;
}

奥普瓯江 发表于 2021-10-30 17:31:09

人造人 发表于 2021-10-30 17:11
很简单,你 malloc 得到的那个地址给了谁,之后就 free 谁
执行了多少次 malloc 就执行多少次 free



收到这回理解了,谢谢啊,没有理解malloc这个函数,麻烦
页: [1]
查看完整版本: 栈、二进制转10进制为什么一到malloc就执行不下去了?