C代码分配了比它应该分配的更多的内存

42fyovps  于 2023-06-05  发布在  其他
关注(0)|答案(1)|浏览(136)

对于一门课程,我正在用C语言做一个时间表式的练习。代码功能齐全,但自动测试显示它分配了416个字节,而实际上应该分配376个字节。这是值a=2,B=9,c=11,d=17。我已经在valgrind上运行了代码,并打开了所有可能的额外细节,但它并没有真正帮助。
我试图将标题行生成作为主时间表创建的一部分,但它最终使用的内存比我当前的方法更多。
destroyTimes函数也应该没有问题,因为valgrind没有报告任何泄漏。
这是时代周刊

#include "times.h"
#include <stdlib.h>
#include <stdio.h>

Times* createTimes(uint a, uint b, uint c, uint d) {
  int i,j;
  int rows=d-c+2;
  int cols=b-a+2;
  
  Times* ret = malloc(sizeof(Times));
  uint** kert = malloc(sizeof(uint*)*rows);

  if (!ret) {
    return NULL;
  }

  ret->a=a;
  ret->b=b;
  ret->c=c;
  ret->d=d;

  kert[0] = malloc(sizeof(uint)*(cols+1)); 
  kert[0][0] = 1;

  for(j=1;j<cols;j++) {
    kert[0][j] = a;
    a++;
  }
  a = ret->a;

  for(i=1;i<rows;i++) {
    kert[i] = malloc(sizeof(uint)*(cols+1));
    for(j=0;j<cols;j++) {
      kert[i][j] = c*kert[0][j];
    }
    c++;
  };

  ret->times = kert;

  return ret;
}

void destroyTimes(Times* kt) {
  uint i;
  uint rows = kt->d - kt->c + 2;
  if (kt == NULL) {
      return;  
  }

  for (i = 0; i < rows; i++) {
      free(kt->times[i]);
  }
  free(kt->times);

  free(kt);
}

这里是times.h

#ifndef TIMES_H
#define TIMES_H

typedef unsigned int uint;

struct Times {
  uint a,b,c,d;
  uint** times;
};

typedef struct Times Times;

Times* createTimes(uint,uint,uint,uint);

void destroyTimes(Times*);

#endif
wa7juj8i

wa7juj8i1#

对于一门课程,我正在用C语言做一个时间表式的练习。
好吧,你想学C。酷...
但是要知道,学习C语言只是完成了一半。您还需要学习如何使用调试器。如何启动调试会话。如何设置断点。如何一步到位如何检查变量值。等等...
现在似乎是做这件事的好时机。
同时,C还带有一个非常强大的内置调试器。它被称为printfnote 1)。
在执行malloc时添加小的调试打印输出将帮助您了解发生了什么。
例如:

printf("rows=%d cols=%d\n", rows, cols);

  size_t total_alloc = 0;
  size_t current_alloc = 0;

  // Times* ret = malloc(sizeof(Times));
  current_alloc = sizeof(Times);
  total_alloc += current_alloc;
  printf("Allocating %zu bytes for Times (total = %zu)\n", current_alloc, total_alloc);
  Times* ret = malloc(current_alloc);

  // uint** kert = malloc(sizeof(uint*)*rows);
  current_alloc = sizeof(uint*)*rows;
  total_alloc += current_alloc;
  printf("Allocating %zu bytes for row-pointers (total = %zu)\n", current_alloc, total_alloc);
  uint** kert = malloc(current_alloc);

  // and likewise for all your malloc

在这样做之后,我可以运行你的程序并得到:

rows=8 cols=9
Allocating 24 bytes for Times (total = 24)
Allocating 64 bytes for row-pointers (total = 88)
Allocating 40 bytes for cols data in row 0 (total = 128)
Allocating 40 bytes for cols data in row 1 (total = 168)
Allocating 40 bytes for cols data in row 2 (total = 208)
Allocating 40 bytes for cols data in row 3 (total = 248)
Allocating 40 bytes for cols data in row 4 (total = 288)
Allocating 40 bytes for cols data in row 5 (total = 328)
Allocating 40 bytes for cols data in row 6 (total = 368)
Allocating 40 bytes for cols data in row 7 (total = 408)

(See* 注2*)
在查看此输出时,很容易发现列中有一些奇怪的地方。9列怎么会需要40个字节?这是每列4.44字节!没道理啊现在来看看malloc列:

kert[i] = malloc(sizeof(uint)*(cols+1));
                                     ^^
                                oh, why did I add one here ???
                                I don't need 10 columns - only 9

在修复代码之后(即删除+ 1两个地方)程序现在将产生:

rows=8 cols=9
Allocating 24 bytes for Times (total = 24)
Allocating 64 bytes for row-pointers (total = 88)
Allocating 36 bytes for cols data in row 0 (total = 124)
Allocating 36 bytes for cols data in row 1 (total = 160)
Allocating 36 bytes for cols data in row 2 (total = 196)
Allocating 36 bytes for cols data in row 3 (total = 232)
Allocating 36 bytes for cols data in row 4 (total = 268)
Allocating 36 bytes for cols data in row 5 (total = 304)
Allocating 36 bytes for cols data in row 6 (total = 340)
Allocating 36 bytes for cols data in row 7 (total = 376)

经验:一些调试打印对于发现bug非常有用。但是,学习如何使用真实的的调试器是很重要的。

  • 注1:不,printf不是调试器。开个玩笑... printf不能替代真实的的调试器,但做一些小的调试打印输出实际上可以非常强大地找到小程序中的bug。
  • 注2:使用您的原始代码,我得到408字节,而您得到416字节。不知道为什么不同,但可能是编译器在结构Times * 中添加了8个字节的填充
    多一点
uint rows = kt->d - kt->c + 2;
  if (kt == NULL) {  <--- Too late... you all ready did the dereference
      return;  
  }

NULL检查必须在**kt->d之前**

相关问题