Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 在手动队列中推送太多的项目——为什么这不是分段错误?_C_Segmentation Fault - Fatal编程技术网

C 在手动队列中推送太多的项目——为什么这不是分段错误?

C 在手动队列中推送太多的项目——为什么这不是分段错误?,c,segmentation-fault,C,Segmentation Fault,我推了7个项目,而我只为5个项目malloc'd,但我没有看到任何故障发生。我错过了什么?我认为这会导致指针移动超过数组边界,并且 #include "stdlib.h" #include "stdio.h" #include "assert.h" typedef struct { int *space; int size; int *start; int *end; } queue_t; typedef char BOOL; #define TRUE 1

我推了7个项目,而我只为5个项目malloc'd,但我没有看到任何故障发生。我错过了什么?我认为这会导致指针移动超过数组边界,并且

#include "stdlib.h"
#include "stdio.h"
#include "assert.h"

typedef struct {
    int *space;
    int size;
    int *start;
    int *end;
} queue_t;

typedef char BOOL;

#define TRUE 1
#define FALSE 0

void queue_print(queue_t *queue) {

    for (int *cur = queue->start; cur < queue->end; cur++) {
        printf("%i,", *cur);
    }

    printf("\n");
}

void queue_init(queue_t **queue, int size) {
    (*queue) = (queue_t*) malloc(sizeof(queue_t));
    (*queue)->space = (int*) malloc(sizeof(int) * size);
    (*queue)->size = size;
    (*queue)->start = (*queue)->space;
    (*queue)->end = (*queue)->space;
}

void queue_push(queue_t *queue, int elem) {
    *(queue->end) = elem;
    queue->end++;
}

int queue_pop(queue_t *queue) {
    int ret = *(queue->start);
    queue->start++;
    return ret;
}

int main(int argc, char const *argv[])
{
    queue_t *queue;
    queue_init(&queue, 5);
    queue_print(queue);
    queue_push(queue, 1);
    queue_print(queue);
    queue_push(queue, 2);
    queue_print(queue);
    queue_push(queue, 3);
    queue_print(queue);
    queue_push(queue, 4);
    queue_print(queue);
    queue_push(queue, 5);
    queue_print(queue);
    queue_push(queue, 6);
    queue_print(queue);
    queue_push(queue, 7);
    queue_print(queue);
    printf("%i\n", queue->size);
    queue->space[123] = 4;
    return 0;
}

C不会检查越界访问,但您的程序会破坏堆,将来再次调用
malloc()
时,您可能会遇到segfault。

您通过调用
队列
分配空间来容纳5个整数。如果在gdb中运行代码,并检查
queue->start
位置的内存,您将看到如下内容:

(gdb) p *queue
(gdb) x/8 0x602450
0x602450:   0   0   0   0
0x602460:   0   0   134049  0
(gdb) x/8 0x602450
0x602450:   1   2   3   4
0x602460:   5   6   7   0
您将看到起始成员的内存地址。在“检查内存”命令中使用该地址,如下所示:

(gdb) p *queue
(gdb) x/8 0x602450
0x602450:   0   0   0   0
0x602460:   0   0   134049  0
(gdb) x/8 0x602450
0x602450:   1   2   3   4
0x602460:   5   6   7   0
gdb将打印如下内容:

(gdb) p *queue
(gdb) x/8 0x602450
0x602450:   0   0   0   0
0x602460:   0   0   134049  0
(gdb) x/8 0x602450
0x602450:   1   2   3   4
0x602460:   5   6   7   0
第5字节之后的所有内容都属于未分配或先前分配的内容。在第7次调用queue_push并再次检查内存后,您会看到如下内容:

(gdb) p *queue
(gdb) x/8 0x602450
0x602450:   0   0   0   0
0x602460:   0   0   134049  0
(gdb) x/8 0x602450
0x602450:   1   2   3   4
0x602460:   5   6   7   0

因此,运行时不会阻止您覆盖未分配或以前分配的内存。但是,您可能写了一些重要的东西,这些东西可能会给运行时或流程中的其他线程带来问题。

这很有趣。你愿意解释一下吗,或者指出一些我可以用来研究这个案例的信息来源?谢谢!这可能会有帮助:可能会导致。更改了答案以解决概率方面的问题。那么,您很可能在下一次malloc中遇到问题。:-)只需在主队列中复制您的代码,并尝试创建另一个队列。叮当作响的静态分析器警告我第二个队列中可能存在内存泄漏。非常好的解释!所以现在我明白发生了什么。但是,如果我可以在数组末尾之外写入,那么什么是segfault呢?我曾经说过:“有四种常见错误会导致分段错误:取消引用NULL、取消引用未初始化的指针、取消引用已释放(或删除,在C++中)或超出范围(在函数中声明数组的情况下)的指针,以及注销数组的结尾。”我想,注销数组的结尾并不总是导致分段错误。这取决于你写什么。一些内存管理器会自动检测到它并抛出运行时错误。此外,当您释放内存时,它很可能会抛出错误。因此,可以在
main
return
之前添加这两行:
free(queue->space);免费(排队)是的。这会直接从内存分配器抛出一个错误。这有多有趣?TKS!SegFault与异常不同:当您违反规则时,它们不会发生,只有当破坏无法恢复时才会发生。您可能会写入超过数组末尾的内容,但幸运的是,该数组位于数组的开头附近,因此有“空间”来破坏其余内存,而不是立即分段出错。没错,
malloc()
完全有可能返回指向堆中任何位置的指针。我想的是一个具体的情况,但页面与主要问题实际上并不相关,你似乎已经理解了这一点。