【问题标题】:Memory allocation error - in Linux but not OSX Unix内存分配错误 - 在 Linux 但不是 OSX Unix
【发布时间】:2012-02-03 07:47:54
【问题描述】:

我正在为一个统计包编写一些代码,我首先将数据读入一个指针数组。我使用 malloc 初始化指针并分配足够的内存;但是,我有时会在下面的代码末尾出现内存分配错误。

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include "stats.h"

int main(int argc, char **argv) {
FILE *fp, *outFile, *outBin;    // create a file identifier
size_t n, nbins; // # of data points
double *data; // pointer to hold data
double average, variance, *med; // stat returns
int medianComplete, histComplete, i; // return 1 on success
hist_t *Histogram;

// read in the number of bins from exe arguments
nbins = atoi(argv[1]);
nbins = (size_t)nbins;

// open the binary datafile and read in first value
// which is number of data points
// use exe input for filename
fp = fopen(argv[2],"rb");
fread(&n, sizeof(size_t),1,fp);

// allocate enough memory to hold all data
data = (double*)malloc(sizeof(double)*n);
if (!data)
    printf("Memory allocation error");
fread(data,sizeof(double),n,fp);

这个程序在我的个人机器 (MacOSX) 上编译和运行良好,但是当我尝试在 Linux 服务器上运行它时由于分段错误而失败。我使用 Valgrind 来查看是否可以追踪错误并收到以下结果。

==8641== Warning: silly arg (-501426814648844128) to malloc()
==8641== Invalid write of size 1
==8641==    at 0x4C2B20D: mempcpy (mc_replace_strmem.c:956)
==8641==    by 0x4EA2F15: _IO_file_xsgetn (fileops.c:1423)
==8641==    by 0x4E971D2: fread (iofread.c:44)
==8641==    by 0x40086D: main (runstats.c:28)
==8641==  Address 0x0 is not stack'd, malloc'd or (recently) free'd

这是我编写的第一个使用指针的程序,我不知道为什么它可以在一个系统上运行,而在另一个系统上不行。

【问题讨论】:

  • 在文件指针的测试中添加,fopen()成功。 Valgrind 表示当我为数据分配内存时发生错误。我对数据执行的检查在服务器上失败,但在我自己的计算机上通过。
  • 当我看到这个问题时,首先想到的是:“当有几十种更合适的语言时,他为什么要在 C 中这样做?..”

标签: c linux memory fault


【解决方案1】:

sizeof(size_t) 取决于平台。在具有默认 32 位代码的 OSX 上,size_t 是 4 个字节。在 64 位 Linux 上,size_t 是 8 个字节。如果您在 64 位 Linux 上运行,那么您阅读的 n 与在 32 位 OSX 上阅读的不同。

如果您必须使用二进制数据格式,请不要使用平台特定类型的大小作为字段大小。确定文件头是 4 字节还是 8 字节,小端还是大端,并始终使用它。

见: What's sizeof(size_t) on 32-bit vs the various 64-bit data models?

【讨论】:

  • 啊!当然。那解决了那个错误。谢谢!现在我从 Valgrind 得到的错误是:“未初始化的值是由堆栈分配创建的”指向我的主要声明。
  • 您还在用fread 阅读size_t 吗?如果您正在读取 4 个字节,请考虑将 freadstdint.h 转换为 uint32_t
【解决方案2】:

您绝对应该在发布之前格式化您的来源...

在执行fread(&amp;n, sizeof(size_t),1,fp); 后使用调试器或打印n 的值。看来你没有得到你期望的值。

【讨论】:

  • 抱歉格式化,我以后一定会这样做的。我已经检查过了,n=20 符合预期。
  • @dwv5009 Valgrind 说不是,假设您发布的代码是 valgrind 抱怨的代码。您是否通过在调用 fread(&amp;n, sizeof(size_t),1,fp); 之后添加 printf("n=%zu\n", n); 来检查 n=20 ?
  • @nos 是的,我就是这么做的。结果是“n=20”。下面的答案修复了它 - 输入文件是在 32 位系统(4 字节)上使用 size_t 写入的,当我尝试在 64 位系统上读取时 size_t 是我输入文件的不正确大小。
  • 你应该在任何事情之前格式化你的源代码,你应该总是在编码时格式化你的源代码。
  • @dwv5009 如果是这样,该行将不会在 64 位机器上打印 20 。 (但如果你使用 printf("%u\n", n); ,甚至 "%d" 而不是 "%zu" ,你可能已经看到 20,即使 n 实际上不是 20)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-17
  • 2016-11-24
  • 1970-01-01
  • 2011-01-11
  • 2015-12-19
  • 2015-09-06
  • 2020-12-28
相关资源
最近更新 更多