C语言push Function中栈中的段错误
Segmentation fault in stack in push Function C language
我在启动程序时遇到了问题,它在函数 Full 和 push 行 70 和 78 (Linux) 处崩溃。我尝试修复它,但我总是在同一个地方崩溃。
#include <stdio.h>
#define SIZE 64
struct stack{
int TowerTop;
int Elem[SIZE];
};
/* Forward Declarations */
void push(int Elem, struct stack *x);
int create (struct stack *x);
int full(const struct stack *x);
void pop(struct stack *x);
int lolol(struct stack *x,struct stack *x2,struct stack *x3,int a);
void main() {
int j;
int a = 5;
//scanf("%d",&a);
struct stack Tower1;
struct stack Tower2;
struct stack Tower3;
create(&Tower1);
create(&Tower2);
create(&Tower3);
for(int i=0; i<=SIZE-1; i++) {
Tower1.Elem[i]=0;
Tower2.Elem[i]=0;
Tower3.Elem[i]=0;
}
for(int i=0; i<=a; i++){
Tower1.Elem[i]=i+1;
}
// Display initial tower setup
for(int i=0; i<a; i++){
printf("%d %7d %7d\n",Tower1.Elem[i],Tower2.Elem[i],Tower3.Elem[i]);
}
lolol(&Tower1,&Tower2,&Tower3,a);
// Display Tower after move made by lolol
printf("%d\n", j);
for(int i=0; i<a; i++) {
printf("%d %7d %7d\n",Tower1.Elem[i],Tower2.Elem[i],Tower3.Elem[i]);
}
}
int lolol(struct stack *x,struct stack *x2,struct stack *x3,int a) {
if(a == 1) {
printf("\n Disk 1 move to");
push(x->Elem[x->TowerTop], x2->Elem[x2->TowerTop]); j++;
pop(x->Elem[x->TowerTop]);
return 0;
}
lolol(x, x3, x2, a-1);
push(x->Elem[x->TowerTop], x2->Elem[x2->TowerTop]); j++;
pop(x->Elem[x->TowerTop]);
lolol(x3, x2, x, a-1);
}
int create(struct stack *x) {
x->TowerTop = -1;
}
int full(const struct stack *x) {
if (x->TowerTop == SIZE-1) {
return 1;
} else {
return 0;
}
}
void push(int Elem, struct stack *x){
if(full(x)) {
printf("Stack is full");
} else {
x->TowerTop++;
x->Elem[x->TowerTop]=Elem;
}
}
void pop( struct stack *x) {
if(x->TowerTop== -1) {
printf("Empty");
} else {
x->TowerTop--;
}
}
我们将一起调试您的代码。但首先,我会告诉你更多关于如何在论坛上提问的信息(因此在 Whosebug 上)。
首先没有 'as fast as possible' 因为我们都在这里提供帮助。我们会尽力而为,它可能准时也可能不准时。然后请用您的代码再次阅读您的消息并问问自己,这是可读的吗?我真的希望你的代码在你的文件中看起来不一样,你只是以某种方式失败了 copy/paste 因为这段代码很难读。
第一步:更改代码以使其可读。
我将跳过这一步的冗长,但基本上它是缩进,在需要时添加空格等。
#include <stdio.h>
#define SIZE 64
struct stack
{
int TowerTop;
int Elem[SIZE];
};
void push(int Elem, struct stack *x);
void pop(struct stack *x);
int create (struct stack *x);
int full(const struct stack *x);
int lolol(struct stack *x, struct stack *x2, struct stack *x3, int a);
int a;
int j;
void main()
{
//scanf("%d", &a);
a = 5;
struct stack Tower1;
struct stack Tower2;
struct stack Tower3;
create(&Tower1);
create(&Tower2);
create(&Tower3);
for (int i = 0; i <= SIZE - 1; i++)
{
Tower1.Elem[i] = 0;
Tower2.Elem[i] = 0;
Tower3.Elem[i] = 0;
}
for (int i = 0; i <= a; i++)
{
Tower1.Elem[i] = i + 1;
}
for (int i = 0; i < a; i++)
{
printf("%d %7d %7d\n", Tower1.Elem[i], Tower2.Elem[i], Tower3.Elem[i]);
}
lolol(&Tower1, &Tower2, &Tower3, a);
printf("%d\n", j);
for (int i = 0; i < a; i++)
{
printf("%d %7d %7d\n", Tower1.Elem[i], Tower2.Elem[i], Tower3.Elem[i]);
}
}
int lolol(struct stack *x, struct stack *x2, struct stack *x3, int a)
{
if (a == 1)
{
printf("\n Disk 1 move to");
push(x->Elem[x->TowerTop], x2->Elem[x2->TowerTop]);
j++;
pop(x->Elem[x->TowerTop]);
return 0;
}
lolol(x, x3, x2, a - 1);
push(x->Elem[x->TowerTop], x2->Elem[x2->TowerTop]);
j++;
pop(x->Elem[x->TowerTop]);
lolol(x3, x2, x, a - 1);
}
int create(struct stack *x)
{
x->TowerTop = -1;
}
int full(const struct stack *x)
{
if (x->TowerTop == SIZE-1)
{
return 1;
}
else
{
return 0;
}
}
void push(int Elem, struct stack *x)
{
if (full(x))
{
printf("Stack is full");
}
else
{
x->TowerTop++;
x->Elem[x->TowerTop] = Elem;
}
}
void pop(struct stack *x)
{
if (x->TowerTop == -1)
{
printf("Empty");
}
else
{
x->TowerTop--;
}
}
请注意,我没有更改任何逻辑或类型等等。
第二步:阅读代码。
实际上我可能稍后会再谈这个,但我快速阅读了一下,有一些基本的东西需要说。 main
函数应始终 returns 和 int
。根据 C 标准,您只能通过两种方式声明 main
函数:int main(void)
(不带参数)或 int main(int argc, char *argv[]);
(带命令行参数)。
那么,你肯定知道a
和j
这两个变量是文件的全局变量。这意味着您可以在同一个源文件中的任何地方访问它们。听起来不错,行不通。你永远不应该做全局变量,除非你没有其他选择(例如使用 sigaction
)。在你的情况下,它们真的不需要。
最后,评论。请推荐你的代码。虽然这里的大部分内容都很容易理解,但函数 lolol
(顺便说一句,这个名字根本没有意义)正在做一些我在快速查看代码时不明白的事情。
第三步:编译
gcc file.c
=> 4 个警告。除非您知道自己在做什么并且是一位经验丰富的 C 程序员——您还不是(现在!),否则您在编译时不应该有任何警告。此外,您应该使用 -Wall -Wextra
开关进行编译。这将抛出更多警告,但允许您在错误存在之前发现它们。
因此我们将修复警告:
warning: return type of ‘main’ is not ‘int’ [-Wmain]
。好吧,让我们换一个。 void main()
变成了 int main(void)
,正如我之前所说的。
file.c:64:34: warning: passing argument 2 of ‘push’ makes pointer from integer without a cast [-Wint-conversion]
=> 好的,这里您使用的是我假设您编写的 push
函数。然而,这个函数需要一个 int
作为它的第一个参数和一个 struct stack *
作为它的第一个参数
第二个参数,当你传递给它一个 int
时。让我们解决这个问题:push(x->Elem[x->TowerTop], x2->Elem[x2->TowerTop]);
变为 push(x->Elem[x->TowerTop], x2);
,因为您将 x->Elem[x->TowerTop]
推到 x2
堆栈的顶部。
- 接下来的三个警告相同,即
pop
第 66 行、push
第 70 行和 pop
第 72 行。
- 接下来的两个警告是相同的:
file.c:74:1: warning: control reaches end of non-void function [-Wreturn-type]
=> 我仍然不确定 lolol
是什么意思,所以我将在下面添加一个 return 0
它结束,并将 create
函数切换为 void
类型。
这是更正后的代码:
#include <stdio.h>
#define SIZE 64
struct stack
{
int TowerTop;
int Elem[SIZE];
};
void push(int Elem, struct stack *x);
void pop(struct stack *x);
void create (struct stack *x);
int full(const struct stack *x);
int lolol(struct stack *x, struct stack *x2, struct stack *x3, int a);
int a;
int j;
int main(void)
{
//scanf("%d", &a);
a = 5;
struct stack Tower1;
struct stack Tower2;
struct stack Tower3;
create(&Tower1);
create(&Tower2);
create(&Tower3);
for (int i = 0; i <= SIZE - 1; i++)
{
Tower1.Elem[i] = 0;
Tower2.Elem[i] = 0;
Tower3.Elem[i] = 0;
}
for (int i = 0; i <= a; i++)
{
Tower1.Elem[i] = i + 1;
}
for (int i = 0; i < a; i++)
{
printf("%d %7d %7d\n", Tower1.Elem[i], Tower2.Elem[i], Tower3.Elem[i]);
}
lolol(&Tower1, &Tower2, &Tower3, a);
printf("%d\n", j);
for (int i = 0; i < a; i++)
{
printf("%d %7d %7d\n", Tower1.Elem[i], Tower2.Elem[i], Tower3.Elem[i]);
}
}
int lolol(struct stack *x, struct stack *x2, struct stack *x3, int a)
{
if (a == 1)
{
printf("\n Disk 1 move to");
push(x->Elem[x->TowerTop], x2);
j++;
pop(x);
return 0;
}
lolol(x, x3, x2, a - 1);
push(x->Elem[x->TowerTop], x2);
j++;
pop(x);
lolol(x3, x2, x, a - 1);
return 0;
}
void create(struct stack *x)
{
x->TowerTop = -1;
}
int full(const struct stack *x)
{
if (x->TowerTop == SIZE-1)
{
return 1;
}
else
{
return 0;
}
}
void push(int Elem, struct stack *x)
{
if (full(x))
{
printf("Stack is full");
}
else
{
x->TowerTop++;
x->Elem[x->TowerTop] = Elem;
}
}
void pop(struct stack *x)
{
if (x->TowerTop == -1)
{
printf("Empty");
}
else
{
x->TowerTop--;
}
}
在没有 SIGSEGV 的情况下编译和 运行ning。
最后一步:更进一步
我将讨论更高级的主题,但它可能对您有用。首先,获取有关堆栈及其工作原理的更多信息,因为我不确定您是否完全理解它。
此外,要调试您的程序,您可以使用 valgrind
,这是一个非常有用的内存检查工具,总是派上用场。要使用它,在编译时添加标志-g
。
我建议也研究 gdb
GNU Linux 调试器。很给力。
函数full
可以改成简单的return x->TowerTop == SIZE - 1
。它避免了分支,因此 运行 更快。
这就是所有人。仍然不确定您的代码应该做什么,但您只询问了如何修复段错误。现在请记住。 编译时不让任何警告。
谢谢。
我在启动程序时遇到了问题,它在函数 Full 和 push 行 70 和 78 (Linux) 处崩溃。我尝试修复它,但我总是在同一个地方崩溃。
#include <stdio.h>
#define SIZE 64
struct stack{
int TowerTop;
int Elem[SIZE];
};
/* Forward Declarations */
void push(int Elem, struct stack *x);
int create (struct stack *x);
int full(const struct stack *x);
void pop(struct stack *x);
int lolol(struct stack *x,struct stack *x2,struct stack *x3,int a);
void main() {
int j;
int a = 5;
//scanf("%d",&a);
struct stack Tower1;
struct stack Tower2;
struct stack Tower3;
create(&Tower1);
create(&Tower2);
create(&Tower3);
for(int i=0; i<=SIZE-1; i++) {
Tower1.Elem[i]=0;
Tower2.Elem[i]=0;
Tower3.Elem[i]=0;
}
for(int i=0; i<=a; i++){
Tower1.Elem[i]=i+1;
}
// Display initial tower setup
for(int i=0; i<a; i++){
printf("%d %7d %7d\n",Tower1.Elem[i],Tower2.Elem[i],Tower3.Elem[i]);
}
lolol(&Tower1,&Tower2,&Tower3,a);
// Display Tower after move made by lolol
printf("%d\n", j);
for(int i=0; i<a; i++) {
printf("%d %7d %7d\n",Tower1.Elem[i],Tower2.Elem[i],Tower3.Elem[i]);
}
}
int lolol(struct stack *x,struct stack *x2,struct stack *x3,int a) {
if(a == 1) {
printf("\n Disk 1 move to");
push(x->Elem[x->TowerTop], x2->Elem[x2->TowerTop]); j++;
pop(x->Elem[x->TowerTop]);
return 0;
}
lolol(x, x3, x2, a-1);
push(x->Elem[x->TowerTop], x2->Elem[x2->TowerTop]); j++;
pop(x->Elem[x->TowerTop]);
lolol(x3, x2, x, a-1);
}
int create(struct stack *x) {
x->TowerTop = -1;
}
int full(const struct stack *x) {
if (x->TowerTop == SIZE-1) {
return 1;
} else {
return 0;
}
}
void push(int Elem, struct stack *x){
if(full(x)) {
printf("Stack is full");
} else {
x->TowerTop++;
x->Elem[x->TowerTop]=Elem;
}
}
void pop( struct stack *x) {
if(x->TowerTop== -1) {
printf("Empty");
} else {
x->TowerTop--;
}
}
我们将一起调试您的代码。但首先,我会告诉你更多关于如何在论坛上提问的信息(因此在 Whosebug 上)。
首先没有 'as fast as possible' 因为我们都在这里提供帮助。我们会尽力而为,它可能准时也可能不准时。然后请用您的代码再次阅读您的消息并问问自己,这是可读的吗?我真的希望你的代码在你的文件中看起来不一样,你只是以某种方式失败了 copy/paste 因为这段代码很难读。
第一步:更改代码以使其可读。
我将跳过这一步的冗长,但基本上它是缩进,在需要时添加空格等。
#include <stdio.h>
#define SIZE 64
struct stack
{
int TowerTop;
int Elem[SIZE];
};
void push(int Elem, struct stack *x);
void pop(struct stack *x);
int create (struct stack *x);
int full(const struct stack *x);
int lolol(struct stack *x, struct stack *x2, struct stack *x3, int a);
int a;
int j;
void main()
{
//scanf("%d", &a);
a = 5;
struct stack Tower1;
struct stack Tower2;
struct stack Tower3;
create(&Tower1);
create(&Tower2);
create(&Tower3);
for (int i = 0; i <= SIZE - 1; i++)
{
Tower1.Elem[i] = 0;
Tower2.Elem[i] = 0;
Tower3.Elem[i] = 0;
}
for (int i = 0; i <= a; i++)
{
Tower1.Elem[i] = i + 1;
}
for (int i = 0; i < a; i++)
{
printf("%d %7d %7d\n", Tower1.Elem[i], Tower2.Elem[i], Tower3.Elem[i]);
}
lolol(&Tower1, &Tower2, &Tower3, a);
printf("%d\n", j);
for (int i = 0; i < a; i++)
{
printf("%d %7d %7d\n", Tower1.Elem[i], Tower2.Elem[i], Tower3.Elem[i]);
}
}
int lolol(struct stack *x, struct stack *x2, struct stack *x3, int a)
{
if (a == 1)
{
printf("\n Disk 1 move to");
push(x->Elem[x->TowerTop], x2->Elem[x2->TowerTop]);
j++;
pop(x->Elem[x->TowerTop]);
return 0;
}
lolol(x, x3, x2, a - 1);
push(x->Elem[x->TowerTop], x2->Elem[x2->TowerTop]);
j++;
pop(x->Elem[x->TowerTop]);
lolol(x3, x2, x, a - 1);
}
int create(struct stack *x)
{
x->TowerTop = -1;
}
int full(const struct stack *x)
{
if (x->TowerTop == SIZE-1)
{
return 1;
}
else
{
return 0;
}
}
void push(int Elem, struct stack *x)
{
if (full(x))
{
printf("Stack is full");
}
else
{
x->TowerTop++;
x->Elem[x->TowerTop] = Elem;
}
}
void pop(struct stack *x)
{
if (x->TowerTop == -1)
{
printf("Empty");
}
else
{
x->TowerTop--;
}
}
请注意,我没有更改任何逻辑或类型等等。
第二步:阅读代码。
实际上我可能稍后会再谈这个,但我快速阅读了一下,有一些基本的东西需要说。 main
函数应始终 returns 和 int
。根据 C 标准,您只能通过两种方式声明 main
函数:int main(void)
(不带参数)或 int main(int argc, char *argv[]);
(带命令行参数)。
那么,你肯定知道a
和j
这两个变量是文件的全局变量。这意味着您可以在同一个源文件中的任何地方访问它们。听起来不错,行不通。你永远不应该做全局变量,除非你没有其他选择(例如使用 sigaction
)。在你的情况下,它们真的不需要。
最后,评论。请推荐你的代码。虽然这里的大部分内容都很容易理解,但函数 lolol
(顺便说一句,这个名字根本没有意义)正在做一些我在快速查看代码时不明白的事情。
第三步:编译
gcc file.c
=> 4 个警告。除非您知道自己在做什么并且是一位经验丰富的 C 程序员——您还不是(现在!),否则您在编译时不应该有任何警告。此外,您应该使用 -Wall -Wextra
开关进行编译。这将抛出更多警告,但允许您在错误存在之前发现它们。
因此我们将修复警告:
warning: return type of ‘main’ is not ‘int’ [-Wmain]
。好吧,让我们换一个。void main()
变成了int main(void)
,正如我之前所说的。file.c:64:34: warning: passing argument 2 of ‘push’ makes pointer from integer without a cast [-Wint-conversion]
=> 好的,这里您使用的是我假设您编写的push
函数。然而,这个函数需要一个int
作为它的第一个参数和一个struct stack *
作为它的第一个参数 第二个参数,当你传递给它一个int
时。让我们解决这个问题:push(x->Elem[x->TowerTop], x2->Elem[x2->TowerTop]);
变为push(x->Elem[x->TowerTop], x2);
,因为您将x->Elem[x->TowerTop]
推到x2
堆栈的顶部。- 接下来的三个警告相同,即
pop
第 66 行、push
第 70 行和pop
第 72 行。 - 接下来的两个警告是相同的:
file.c:74:1: warning: control reaches end of non-void function [-Wreturn-type]
=> 我仍然不确定lolol
是什么意思,所以我将在下面添加一个return 0
它结束,并将create
函数切换为void
类型。
这是更正后的代码:
#include <stdio.h>
#define SIZE 64
struct stack
{
int TowerTop;
int Elem[SIZE];
};
void push(int Elem, struct stack *x);
void pop(struct stack *x);
void create (struct stack *x);
int full(const struct stack *x);
int lolol(struct stack *x, struct stack *x2, struct stack *x3, int a);
int a;
int j;
int main(void)
{
//scanf("%d", &a);
a = 5;
struct stack Tower1;
struct stack Tower2;
struct stack Tower3;
create(&Tower1);
create(&Tower2);
create(&Tower3);
for (int i = 0; i <= SIZE - 1; i++)
{
Tower1.Elem[i] = 0;
Tower2.Elem[i] = 0;
Tower3.Elem[i] = 0;
}
for (int i = 0; i <= a; i++)
{
Tower1.Elem[i] = i + 1;
}
for (int i = 0; i < a; i++)
{
printf("%d %7d %7d\n", Tower1.Elem[i], Tower2.Elem[i], Tower3.Elem[i]);
}
lolol(&Tower1, &Tower2, &Tower3, a);
printf("%d\n", j);
for (int i = 0; i < a; i++)
{
printf("%d %7d %7d\n", Tower1.Elem[i], Tower2.Elem[i], Tower3.Elem[i]);
}
}
int lolol(struct stack *x, struct stack *x2, struct stack *x3, int a)
{
if (a == 1)
{
printf("\n Disk 1 move to");
push(x->Elem[x->TowerTop], x2);
j++;
pop(x);
return 0;
}
lolol(x, x3, x2, a - 1);
push(x->Elem[x->TowerTop], x2);
j++;
pop(x);
lolol(x3, x2, x, a - 1);
return 0;
}
void create(struct stack *x)
{
x->TowerTop = -1;
}
int full(const struct stack *x)
{
if (x->TowerTop == SIZE-1)
{
return 1;
}
else
{
return 0;
}
}
void push(int Elem, struct stack *x)
{
if (full(x))
{
printf("Stack is full");
}
else
{
x->TowerTop++;
x->Elem[x->TowerTop] = Elem;
}
}
void pop(struct stack *x)
{
if (x->TowerTop == -1)
{
printf("Empty");
}
else
{
x->TowerTop--;
}
}
在没有 SIGSEGV 的情况下编译和 运行ning。
最后一步:更进一步
我将讨论更高级的主题,但它可能对您有用。首先,获取有关堆栈及其工作原理的更多信息,因为我不确定您是否完全理解它。
此外,要调试您的程序,您可以使用 valgrind
,这是一个非常有用的内存检查工具,总是派上用场。要使用它,在编译时添加标志-g
。
我建议也研究 gdb
GNU Linux 调试器。很给力。
函数full
可以改成简单的return x->TowerTop == SIZE - 1
。它避免了分支,因此 运行 更快。
这就是所有人。仍然不确定您的代码应该做什么,但您只询问了如何修复段错误。现在请记住。 编译时不让任何警告。
谢谢。