
这是我的环境:
下面是我的实现代码:
#include "stdio.h" #include "stdlib.h" #define OK 1 #define ERROR 0 #define CAPACITY 10 typedef int Status; typedef int ElementType; StatusinitQueue(); Status isEmpty(); Status isFull(); Status enQueue(); Status deQueue(); typedef struct { ElementType *array; int front, rear; int capacity; int size; } *Queue; int main(void) { Queue q = NULL; initQueue(&q); enQueue(q, 1); enQueue(q, 2); enQueue(q, 3); int foo; deQueue(q, &foo); deQueue(q, &foo); deQueue(q, &foo); printf("%d", foo); return 0; } Status initQueue(Queue *q) { (*q) = (Queue)malloc(sizeof(Queue)); (*q)->capacity = CAPACITY; printf("capacity = %d\n", (*q)->capacity); (*q)->array = (ElementType *)malloc((*q)->capacity * sizeof(ElementType)); (*q)->frOnt= (*q)->size = 0; (*q)->rear = (*q)->capacity - 1; printf("queue = %p, capacity = %d, size = %d, frOnt= %d, rear = %d, array = %p\n", (*q), (*q)->capacity, (*q)->size, (*q)->front, (*q)->rear, (*q)->array); return OK; } Status isEmpty(Queue q) { if (q->size == 0) { printf("Queqe is empty\n"); return OK; } return ERROR; } Status isFull(Queue q) { if (q->size == q->capacity) { printf("Queqe is full\n"); return OK; } return ERROR; } Status enQueue(Queue q, ElementType e) { if (isFull(q)) { return ERROR; } q->rear = (q->rear + 1) % q->capacity; q->array[q->rear] = e; q->size++; printf("%d enqueued to queue\n", e); return OK; } Status deQueue(Queue q, ElementType *e) { if (isEmpty(q)) { return ERROR; } *e = q->array[q->front]; q->frOnt= (q->front + 1) % q->capacity; q->size--; printf("%d dequeued from queue\n", *e); return OK; } 这个有意思的问题就是在终端中执行结果不太一致
比如我在 VS code 中的集成终端中( CMD )使用 GCC 编译并执行会是这样的结果:
gcc SequenceQueue.c -o SequenceQueue && SequenceQueue.exe capacity = 10 queue = 006B1810, capacity = 10, size = 0, frOnt= 0, rear = 9, array = 006B1850 1 enqueued to queue 2 enqueued to queue 3 enqueued to queue 1 dequeued from queue 2 dequeued from queue 3 dequeued from queue 3 如果将集成终端换成 PowerShell,却是这样的结果:
gcc SequenceQueue.c -o SequenceQueue; .\SequenceQueue capacity = 10 queue = 00A015F0, capacity = 268435466, size = 0, frOnt= 0, rear = 268435465, array = 00A01600 1 enqueued to queue 2 enqueued to queue 3 enqueued to queue 4 dequeued from queue 2 dequeued from queue 3 dequeued from queue 3 这 tm 太奇怪了,capacity 咋就变了,rear 是 capacity - 1 才是这样的结果,而且第一个出栈不是 1 而是 4,很明显 CMD 执行的是正确的结果,也不知道 PowerShell 发生了什么。为了排除 VS Code 的原因,直接单独打开 CMD 和 PowerShell 测试
CMD:
gcc SequenceQueue.c -o SequenceQueue && SequenceQueue capacity = 10 queue = 007915B8, capacity = 10, size = 0, frOnt= 0, rear = 9, array = 007915F0 1 enqueued to queue 2 enqueued to queue 3 enqueued to queue 1 dequeued from queue 2 dequeued from queue 3 dequeued from queue 3 PowerShell:
gcc SequenceQueue.c -o SequenceQueue; .\SequenceQueue capacity = 10 queue = 001F2AD0, capacity = 134217738, size = 0, frOnt= 0, rear = 134217737, array = 001F2AE0 1 enqueued to queue 2 enqueued to queue 3 enqueued to queue 4 dequeued from queue 2 dequeued from queue 3 dequeued from queue 3 这看起来和 VS Code 本身没啥关系,似乎 PowerShell 有点问题?把编译和运行命令分开执行试一下
gcc .\SequenceQueue.c -o .\SequenceQueue .\SequenceQueue capacity = 10 queue = 00E62AD0, capacity = 134217738, size = 0, frOnt= 0, rear = 134217737, array = 00E62AE0 1 enqueued to queue 2 enqueued to queue 3 enqueued to queue 4 dequeued from queue 2 dequeued from queue 3 dequeued from queue 3 好吧,看起来还是不行,capacity 的值乱七八糟,第一个出栈的还是 4 而不是 1 。但是,如果不指定生成后的文件名,PowerShell 它似乎又正确了
(默认生成的 exe 程序名为 a)
gcc .\SequenceQueue.c .\a.exe capacity = 10 queue = 00B22E40, capacity = 134217738, size = 0, frOnt= 0, rear = 134217737, array = 02144020 1 enqueued to queue 2 enqueued to queue 3 enqueued to queue 1 dequeued from queue 2 dequeued from queue 3 dequeued from queue 3 但是 capacity 又是乱七八糟的值,那么可能是 GCC 编译的时候出现了问题?于是在 CMD 中使用 GCC 编译并执行程序,然后在 PowerShell 中执行程序
这是 CMD 中的执行结果:
gcc SequenceQueue.c -o SequenceQueue SequenceQueue.exe capacity = 10 queue = 00BB15B8, capacity = 10, size = 0, frOnt= 0, rear = 9, array = 00BB15F8 1 enqueued to queue 2 enqueued to queue 3 enqueued to queue 1 dequeued from queue 2 dequeued from queue 3 dequeued from queue 3 这是 PowerShell 中的执行结果:
.\SequenceQueue.exe capacity = 10 queue = 001E2AD0, capacity = 134217738, size = 0, frOnt= 0, rear = 134217737, array = 001E2AE0 1 enqueued to queue 2 enqueued to queue 3 enqueued to queue 4 dequeued from queue 2 dequeued from queue 3 dequeued from queue 3 不是吧,PowerShell 咋回事?那么在 PowerShell 中编译并执行,然后在 CMD 中执行
这是 PowerShell 的:
gcc .\SequenceQueue.c .\SequenceQueue.exe capacity = 10 queue = 00AB2AD0, capacity = 134217738, size = 0, frOnt= 0, rear = 134217737, array = 00AB2AE0 1 enqueued to queue 2 enqueued to queue 3 enqueued to queue 4 dequeued from queue 2 dequeued from queue 3 dequeued from queue 3 这是 CMD 的:
gcc SequenceQueue.c -o SequenceQueue SequenceQueue.exe capacity = 10 queue = 00B515B8, capacity = 10, size = 0, frOnt= 0, rear = 9, array = 00B515F8 1 enqueued to queue 2 enqueued to queue 3 enqueued to queue 1 dequeued from queue 2 dequeued from queue 3 dequeued from queue 3 妈妈,我想放弃学习了,这都啥跟啥啊,真想一脚踩烂 PowerShell 。好吧,也许不是 GCC 的锅,目前为止我也不知道代码实现是否有哪个地方的问题导致这样的结果,所以希望各位大佬能否复刻一下这种情况,产生这个问题的原因是,我使用 VScode 某个插件一键调用 GCC 编译且执行,总是得到 PowerShell 的结果,然后调试了半天发现不知道问题在哪,于是将代码换到了一些在线运行 C 的网站,发现我的代码似乎没什么太大问题,于是才有了这样的疑问
1 typetraits 2021-07-30 19:37:28 +08:00 你的代码里面的 ```C typedef struct { ElementType *array; int front, rear; int capacity; int size; } *Queue; ``` 实际上`Queue`是指向一个匿名结构体的指针,Queue 的大小就是一个指针的大小,32 位上 4 字节,64 位上 8 字节 所以导致你的 initQueue 中 malloc()实际只分配了 8 个字节,赋值操作已经内存溢出了 |
2 typetraits 2021-07-30 19:39:09 +08:00 说错了,看你的 printf 输出的地址,你的系统是 32 位的,那么 Queue 就是 4 字节 |
3 nightwitch 2021-07-30 19:42:27 +08:00 Status initQueue(); Status initQueue(Queue *q) { } 函数声明和函数实现对不上,放新一点的编译器直接报编译错误。 |
4 nightwitch 2021-07-30 19:43:13 +08:00 malloc(sizeof(Queue)) 分配的内存分配少了。 |
5 wevsty 2021-07-30 20:05:34 +08:00 代码的槽点很多,看的血压升高。 1 、声明和定义需要一致,不要去糊弄编译器。 Status initQueue(); Status initQueue(Queue *q); 完全是 2 个不同的东西。 2 、指针和结构体在命名的时候需要区分。 Queue 这个类型名尽管看上去可能像结构体,但是实际定义成了指针。 命名不明确这就给你的代码留下了坑。 3 、sizeof 求的是类型所占用的空间。 sizeof(Queue) = 指针所占用的大小 所以 initQueue 中你并没有为结构体真正的分配空间,那么后续的一切内存操作都是未定义的。 |
6 JQiue OP 原来如此,多谢各位大佬 |
7 JQiue OP 我回去按照各位指出的错误修改了一下代码,确实运行正常了,多谢各位解惑 |
8 JQiue OP @nightwitch 额外请教一下,这个声明是必须要写上参数类型么,我没有注意到这个问题 |
9 YsHaNg 2021-07-30 21:06:47 +08:00 @JQiue 声明不写参数类型像你那样那是不接受参数的函数 后面定义又给了参数那就是两个东西 C++是合法的 C 是不能重用函数名的 |
11 kilasuelika 2021-07-30 21:18:12 +08:00 via Android 用 C++就不会有这么多毛病 |
12 raysonx 2021-07-30 21:36:09 +08:00 @YsHaNg 传统上 C 语言里面不写参数类型是指可以接受任意多个参数(...),参数与成 void 比如 int foo(void); 才是不接受参数。。。 |
13 YsHaNg 2021-07-30 22:37:34 +08:00 @raysonx Variadic function?要用<stdio.h>的啊 plain f([nothing_here])和它不等效吧 |
16 ezrameow 2021-07-31 01:57:51 +08:00 @JQiue 不同终端运行不正常是因为读取未初始化的内存部分是 ub,返回什么都很正常,而且一般受内存分布和初始化环境影响。。。 |
17 uyun2421 2021-07-31 12:41:14 +08:00 via iPhone s |
18 uyun2421 2021-07-31 12:41:30 +08:00 via iPhone 和 |
19 icyalala 2021-07-31 13:22:41 +08:00 编译加上 -Wall -Wextra,有 warning 都看一下,不然自己错哪里怎么错的都弄不清。。 |
20 jedihy 2021-07-31 16:01:41 +08:00 跟 powershell 没任何关系。出现这种问题说明你的程序在读未初始化内存的或者非法的访问。 |
21 araraloren 2021-08-02 12:21:03 +08:00 改用 rust 就不会有这么多毛病了 |