在函数中使用malloc?

时间:2014-09-03 01:27:33

标签: c malloc

我是malloc的新手。所以我想测试这个小代码。 我收到"分段错误错误"。

**编辑:问题来自不分配char *名称(感谢@Zack) 您可以看到导致问题的原因:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct info { char *name; } fileinfo;

void mal (fileinfo **ptr)
{   
if ((*ptr = (fileinfo*) malloc(3*sizeof(fileinfo))) == NULL) {
    fprintf(stderr,"Memory allocating error #1\n");
    exit(1);
    }
//that what was causing the error - START
for (j = 0; j < 3; j += 1)
    {
    (*ptr)[j].name = (char*) malloc(10*sizeof(char*));
    }
//that what was causing the error - END
    strcpy(ptr[0]->name,"1. A\n");                        //line 13
    strcpy(ptr[1]->name,"2. B\n");
    strcpy(ptr[2]->name,"3. C\n");
}

int main (int argc, char *argv[])
{
fileinfo *files;
int i;
mal(&files);                                             //line 22
for (i = 0; i < 3; i += 1)
{
    printf("name=%s\n",files[i].name);
}
free(files);
return 0;
}

使用valgrind:

==5751== Use of uninitialised value of size 8
==5751==    at 0x4006EB: mal (mal1.c:13)
==5751==    by 0x400747: main (mal1.c:22)
==5751== 
==5751== Invalid write of size 4
==5751==    at 0x4006EB: mal (mal1.c:13)
==5751==    by 0x400747: main (mal1.c:22)
==5751==  Address 0x0 is not stack'd, malloc'd or (recently) free'd

我做错了什么?! 提前谢谢。

2 个答案:

答案 0 :(得分:1)

您的问题是您需要在复制之前分配ptr [i] - &gt;名称。指针本身指向一些随机的内存区域。要使用它,你必须获得安全的良好内存,这就是malloc和calloc以及(C ++中的新功能)所做的一切。你给出的例子仍然是一团糟,我的纠正并不是那么好,但你知道C和C ++中的每个指针都必须从某个地方分配。而且,另一方面,一旦你完成指针,你必须释放它们。

void mal (fileinfo **ptr, int count)
{   
    if ((*ptr = (fileinfo*) malloc(count*sizeof(fileinfo))) == NULL) {
      fprintf(stderr,"Memory allocating error #1\n");
      exit(1);
    }
    for (int i = 0; i < 3; i++) {
       char buff[2];
       buff[0] = 'A' + i;
       buff[1] = 0;
       ptr[i]->name = malloc( 10 );
       strcpy(ptr[0]->name,"1. %s\n", buff);                        
    }
}

答案 1 :(得分:0)

尝试

void mal (fileinfo **ptr) {   
  if ((*ptr = malloc(3*sizeof(fileinfo))) == NULL) {
   perror("Memory allocating error #1\n");
   exit(EXIT_FAILURE);
  }
  if (!(ptr[0]->name = strdup("1. A\n"))) 
    { perror("string 1"); exit(EXIT_FAILURE);};                      
  if (!(ptr[1]->name = strdup("2. B\n")))
    { perror("string 2"); exit(EXIT_FAILURE);};    
  if (!(ptr[2]->name = strdup("3. C\n")))
    { perror("string 3"); exit(EXIT_FAILURE);} ;
}
顺便说一下,最好让它成为一个返回指针的函数,比如

 fileinfo* make() {
   fileinfo* ptr = malloc(3*sizeof(fileinfo)));
   if (!ptr) { perror("make fileinfo"); exit(EXIT_FAILURE); };
  if (!(ptr[0]->name = strdup("1. A\n"))) 
    { perror("string 1"); exit(EXIT_FAILURE);};                      
  if (!(ptr[1]->name = strdup("2. B\n")))
    { perror("string 2"); exit(EXIT_FAILURE);};    
  if (!(ptr[2]->name = strdup("3. C\n")))
    { perror("string 3"); exit(EXIT_FAILURE);} ;
  return ptr;
 }

然后,你需要一个像

这样的析构函数
void destroy(fileinfo*ptr) {
  free (ptr[0]->name);
  free (ptr[1]->name);
  free (ptr[2]->name);
  free (ptr);
}
在您free

的末尾调用

而不是main

请注意,您的代码非常临时:名称的数量(即3)是完全内置的。这是错误的设计。至少应该将该常量命名为:

 #define NB_FILES 3

实际上,更好的方法是使用灵活的数组成员声明您的结构:

typedef struct fileinfo_st { 
   unsigned nbfiles;
   char* filenames[]; 
} Fileinfo;

有关详情,请参阅this。你甚至可以使用一个可变函数来制作这样的结构。

FIleinfo *make(int, ...);

您可以称之为

Fileinfo* ptr = make (3, "abc","def","ghijklmnop");

或者你可以决定最后一个可变参数是NULL

BTW,请阅读undefined behavior。你可能不幸的是你的程序没有崩溃但仍然是非常错误的。并使用gcc -Wall -g进行编译,详细了解如何使用gdb调试器和valgrind