2015-03-03 17 views
0

这个函数将倒带文件,创建所述动态阵列(大小),而在数据读取,填充_data结构动态数组。请注意,流 这次是按值传递的。该函数然后返回填充 阵列结构倒带文件,创建动态STRUCT

struct _data 
{ 
    char* name; 
    long number; 
}; 

struct _data *load(FILE *stream, int size) 
{ 
    struct _data BlackBox = calloc(size, sizeof(_data)); 

    char tempName[3]; 

    stream = fopen("names.txt", "r"); 
    for (int i=0; i<size; i++) 
    { 
     fscanf(stream, "%s %ld", tempName, &data.number); 
     BlackBox[i].name = calloc(strlen(tempName), sizeof(char)); 
     strcpy(BlackBox[i].name, tempName); 
    } 
    fclose(stream); 

    return &BlackBox; 
} 

File Content 
ron 7774013 
jon 7774014 

我是一个初学者和有困难的设计代码。有人可以请解释。由于

+0

你的问题是什么? – 2015-03-03 04:21:24

+0

@QmickZh \t 代码不能编译。我想将文件的内容加载到结构中。函数(* load)将被main调用。 – user3337714 2015-03-03 04:39:31

+0

此代码的所有错误都可以在编译器输出中轻松找到。你应该先阅读它。 – 2015-03-03 04:39:59

回答

1

我认为你必须从GCC一定的警示作用,以帮助您。

修复内存管理与释放calloc,并没有返回堆栈指针

typedef struct _data               
{                    
    char* name;                 
    long number;                
} _data;                  

_data *load(FILE *stream, int size)            
{                    
    _data *BlackBox = calloc(size, sizeof(_data));        

    char tempName[3];               

    for (int i=0; i<size; i++)             
    {                   
     fscanf(stream, "%s %ld", tempName, &BlackBox[i].number);    
     BlackBox[i].name = strdup(tempName);         
    }                   
    fclose(stream);                

    return BlackBox;               
}                    

int main (void)                 
{                    
    FILE *f = fopen("test.data", "r");           
    _data *data = load(f, 2);             
    printf("%s %ld\n", data[0].name, data[0].number);       
    printf("%s %ld\n", data[1].name, data[1].number);       
    return 0;                 
} 

输出

[email protected]:~$ ./a.out 
ron 7774013 
jon 7774014 

想想变化_data

typedef struct _data{ 
    char name[256]; 
    long number; 
} _data; 

扫描将是:

for (int i=0; i<size; i++)             
{                   
    fscanf(stream, "%s %ld", BlackBox[i].name, &BlackBox[i].number);  
} 
+0

我在使用程序后遇到了多个错误。我如何在这里发布他们? – user3337714 2015-03-03 04:55:00

+0

'main.c:70:26:error:array type'char [256]'is not assignable BlackBox [i] .name = strdup(tempName); ~~~~~~~~~~~~~~~~ ^' – user3337714 2015-03-03 04:59:54

+0

只能使用第一部分,你已经混合我的第一和第二个命题 – 2015-03-03 05:11:09

0

你与你以前的帖子作出同样的arrors。您也不会为_data中的name成员分配内存。至于编译错误:

T类型,你用 malloccalloc由手柄,一个指向 T*类型的 T控制的动态分配的
  • 阵列。
  • 你定义的结构是struct _data类型,类型包括关键字struct。如果你想为你的类型使用单字标识符,可以使用'Ôrel'向你显示的'typedef'。
  • 你不变量称为'data . The handle to the newly allocated memory is ´BlackBox

如果您修复这些错误,你会遇到逻辑错误,编译器不能知道:

  • BlackBox[i].name通过calloc初始化为NULL,所以它并不指向有效的内存。你不能将任何东西放入其中。你可以做的是使用非标准但广泛可用的strdup,它首先根据需要分配内存然后复制。
  • 您的临时字符串长度为3;它最多可以容纳两个字符加上空终止符。文件中的名称很短,但是您的程序必须为任何输入做准备,甚至是非法输入。
  • FILE *不在您的函数外部使用;它应该是load的本地。
  • 用户必须指定要读取的项目数。这违背了动态分配的目的。用户也不知道有多少项被读取;根据请求,文件中的项目可能会更少。你的功能设计应该反映这一点。(好吧,这不是真的:你零初始化的内存,这意味着一个字符指针NULL信号数组的末尾,但:)
  • 你不测试fscanf,你应该输出。如果您的文件的项数少于size,则最后一项将包含垃圾,因为您将垃圾值复制到零初始化的内存中。
  • 不是错误本身,但如果你的文件一起组织起来,可以考虑读一本线与fgets,然后再解析与sscanf

以下示例代码试图将这些准则。注意事项:

  • 内存不是分配在一个巨大的块中,但随着对realloc的后续调用,内存不断增大。致电realloc(NULL, s)相当于malloc(s)
  • 函数通过指向整数的指针“读取”元素的数量。
  • 字符串被复制到新分配的内存中。这意味着理论上,弦线可以随意长。 (实际上,最大缓冲区长度为20的这种字符串短小。)函数duplicate模拟函数strdup
  • 清理时这些字符串应该是free d。
  • load函数采用文件名来代替文件句柄。
  • 文件读取分两个阶段进行:先读一行,然后扫描这一行。如果格式不是“没有空格的字符串”+“数字”,则写入错误消息。

无论如何,这里有云:

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

struct _data 
{ 
    char *name; 
    long number; 
}; 

/* 
*  Duplicate a string on the heap (aka strdup) 
*/ 
char *duplicate(const char *str) 
{ 
    char *p = malloc(strlen(str) + 1); 

    strcpy(p, str); 
    return p; 
} 

/* 
*  Read a list of names from file fn 
*/ 
struct _data *load(const char *fn, int *psize) 
{ 
    struct _data *data = NULL; 
    FILE *stream; 
    char line[80];  // buffer for line 
    int lnr = 0;  // line number for error message 
    int n = 0;   // number of read items 

    stream = fopen("names.txt", "r"); 
    if (stream == NULL) return NULL; // Can't open file 

    while (fgets(line, sizeof(line), stream)) { 
     long int number; 
     char buf[20]; 

     lnr++; 
     if (sscanf(line, "%19s %ld", buf, &number) == 2) { 
      data = realloc(data, (n + 1) * sizeof(*data)); 
      data[n].number = number; 
      data[n].name = duplicate(buf); 
      n++; 
     } else { 
      fprintf(stderr, "[%s, line %d] Illegal format\n", fn, lnr); 
     } 
    } 
    fclose(stream); 
    *psize = n;    // Assign number of read items 

    return data; 
} 

/* 
*  Free memory allocated by load 
*/ 
void cleanup(struct _data *data, int n) 
{ 
    while (n--) free(data[n].name); 
    free(data); 
} 

int main() 
{ 
    struct _data *data; 
    int i, n; 

    data = load("names.txt", &n); 
    if (data == NULL) return -1; 

    for (i = 0; i < n; i++) { 
     printf("%-20s%12ld\n", data[i].name, data[i].number); 
    } 

    cleanup(data, n); 

    return 0; 
} 
+0

我会记得。我对Ruby和Java很好,但是C对我来说只是一些新东西。我很抱歉,我非常感谢你的解释。 – user3337714 2015-03-03 06:58:19

+0

Ruby和Java以及大多数现代语言为您处理内存分配和垃圾收集。在C中,你必须照顾好自己。这可以导致优化设计,但这也意味着你经常在脚下自己射击,特别是当你还在学习时。以上的建议采取一粒盐。评论和示例代码旨在帮助,而不是冒犯。 – 2015-03-03 07:04:59

+0

我接受了每一条建议,但我不觉得它们令人反感。对我而言,这永远是学习的时刻,我会从中学习。我假设,你能否给我一本好书,以开始理解C.我知道Ruby和Java中的垃圾收集。 C真的让我走了。 :( – user3337714 2015-03-03 07:13:46

0

...,最后tempName [3]是太小了​​:它必须是至少4,给你3个字母的输入。此外,你忘了你的malloc调用分配空间终止空字符:

char tempName[4]; 
... 
BlackBox[i].name = malloc(strlen(tempName)+1); 

(即tempName [3]并没有导致错误,是因为编译器可能四舍五入它为偶数字节 - 但这是一个典型的初学者的错。)

+0

将在我未来的代码考虑。 – user3337714 2015-03-03 08:23:08