【问题标题】:segmentation fault on calloc with small allocation sizes分配大小较小的 calloc 上的分段错误
【发布时间】:2017-06-18 20:05:36
【问题描述】:

我编写了代码来模拟选举,这可以按预期工作,但是当我将 BALLOT_SIZE 修改为 7,并在 New_Random_Ballot() 中更改 int v[BALLOT_SIZE] = {0,1,2,3,4,5,6} 的定义时,语句 struct Ballot * New_Ballot = calloc(1, sizeof(struct Ballot *)); 给了我一个分段过错。需要注意的是,将 BALLOT_SIZE 设置为 6 并修改 int v[BALLOT_SIZE] = {0,1,2,3,4,5} 的定义以及这些变量的所有较小设置(例如长度 4、3 或 2)都可以正确执行。为了清楚起见,我删除了对数组进行洗牌的代码。

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#define BALLOT_SIZE 5
#define NUM_VOTERS 50

struct Ballot {
    int votes[BALLOT_SIZE];
};

struct Ballot * New_Random_Ballot() {

    int v[BALLOT_SIZE] = {0,1,2,3,4}; 
    struct Ballot * New_Ballot = calloc(1, sizeof(struct Ballot *));

    for (int j = 0; j < BALLOT_SIZE; j++) {
        New_Ballot->votes[j] = v[j];
    }
    return New_Ballot;
}

void Hold_Election(struct Ballot * Election[NUM_VOTERS]) {
    for (int i=0; i < NUM_VOTERS; i++) {
        Election[i] = New_Random_Ballot();
    }   
}

int main() {
    struct Ballot * Election[NUM_VOTERS];
    Hold_Election(Election);

    //free memory
    for (int i=0; i < NUM_VOTERS; i++) {
        free(Election[i]);
    }
    return 0;
}

我已经尝试捕获 calloc 调用的返回值并对照 NULL 检查它,但在它能够检查返回值之前,它出错了(在本例中,BALLOT_SIZE 为 7):

struct Ballot * New_Random_Ballot() {

    int v[BALLOT_SIZE] = {0,1,2,3,4,5,6}; 
    struct Ballot * New_Ballot = calloc(1, sizeof(struct Ballot *));

    if (New_Ballot == NULL) {
        perror("could not allocate ballot\n");
    }

    for (int j = 0; j < BALLOT_SIZE; j++) {
        New_Ballot->votes[j] = v[j];
    }
    return New_Ballot;
}

【问题讨论】:

  • calloc(1, sizeof(struct Ballot *)) --> calloc(1, sizeof(struct Ballot)) 因为sizeof(struct Ballot *) 是指针大小。不是对象大小。
  • sizeof(struct Ballot *) 指针不是它指向的对象!
  • sizeof(struct Ballot) == BALLOT_SIZE * sizeof(int),而 sizeof(struct Ballot*) == sizeof(void*) == 4(或 8 对于 64 位应用程序)。 * 有很大的不同。

标签: c


【解决方案1】:

问题出在这里:

calloc(1, sizeof(struct Ballot *));  // Ballot* is a pointer of size 4 or 8

替换为:

calloc(1, sizeof(struct Ballot));  // struct Ballot is a structure of some size

正如下面@Olaf 正确指出的那样,指针大小可能取决于CPU。上面的原始答案需要澄清一下。

对于任何数据类型、结构或联合 AnyType,ISO 标准都保证了这种平等:

sizeof(AnyType*) == sizeof(void*)

void* 的大小由 CPU 架构定义。在 32 位平台上,指针长度为 4 字节,在 64 位平台上,指针长度为 8 字节。

在 16 位平台上,例如 i386,指针通常为 16 位长,但也有远指针,sizeof(void far*)通常为 32 位(16 位用于段, 16 位地址)。

在 8 位平台上,例如 i8051,逻辑会规定指针为 8 位宽,但这不是很有用,因此在 8 位 CPU 上指针通常为 16 位宽。在 8 位 CPU 上通常没有与指针相关的段,而管理远内存是程序员的责任。即通过设置适当的控制寄存器来更改可见的扩展内存页面。

【讨论】:

  • 你确定吗?
  • "Ballot* 是大小为 4 或 8 的指针" - 请提供对保证指针为 4 或 8 字节的标准的参考! 12 字节的现有实现是否不兼容?
  • 所以我用struct Ballot * New_Ballot 创建一个指针,然后指向一个Ballot 结构大小的空间区域,而不是指向一个与指针大小相同的空间?
  • 相反,但这就是想法。每次你用错误的大小调用 calloc,然后写,你正在破坏堆。您是否考虑过调用 malloc?
  • calloc 有2个参数,专门用于分配数组。 malloc 只有一个参数。除了提高一点效率和一点点可读性之外,没有其他优势。
猜你喜欢
  • 1970-01-01
  • 2011-08-05
  • 2014-12-02
  • 2022-01-08
相关资源
最近更新 更多