2016-11-28 88 views
1

我想创建一个指针数组,指向我的理解。但是,我正在使用valgrind运行读取和写入无效。使用C创建一个动态的字符数组指针指针

char **format_file(FILE *infile) { 
    char **char_array = malloc(20 * sizeof(char*)); 
    int c; 
    int cUsed = 0; 

    while ((c = fgetc(infile)) != EOF) { 
     char_array[cUsed] = c; 
     cUsed += 1; 
    } 

    printf("%s", *char_array); 
    return char_array; 
} 

该代码通过从已打开的文件“infile”中读取而工作。首先我用malloc为20个字符分配了内存,然后我试图按字符将文件字符读入分配的内存数组中,直至达到F到达EO。然而,的valgrind的输出如下所示,当我使代码:

==7379== Invalid read of size 1 
==7379== at 0x4E7CB36: vfprintf (vfprintf.c:1597) 
==7379== by 0x4E85198: printf (printf.c:35) 
==7379== by 0x400755: format_file (formatter.c:27) 
==7379== by 0x4006C1: main (format265alt.c:21) 
==7379== Address 0x6f is not stack'd, malloc'd or (recently) free'd 

线27是printf命令的valgrind称之为尺寸1.

formatter.c由含有所述文件的无效的读format265alt.c是一个调用formatter.c函数并打开要读取的文件的文件。

我对**的语法感到困惑,那就是如何访问和读写分配的内存?

如果我没有提供有关此问题的足够信息,我表示歉意。

+1

'CHAR_ARRAY [cUsed]'是'型将char *''不过是C'型'int'的。在那里看到问题? – kaylum

+0

没错,但即使我把c变成角色,它仍然不起作用。 –

+0

你为什么要施放它?铸造不是魔术。除非你知道你在做什么,否则不要这样做。关键是你的类型是错误的。解决这个问题(并且不,铸造不是这样)。 – kaylum

回答

0

valgrind抱怨,因为您存储的字符超出了分配的对象的末尾。编译器应该抱怨你正在将字符存储到错误类型的对象中,请使用-Wall -W来启用有用的警告。

A char **是一个指向char指针的指针,它可以指向一个char指针数组,也被称为字符串数组。您必须为文件内容分配适当大小的阵列和每个字符串。

在这里有两种可能性:

  • 功能可以将整个文件加载到一个字符串,但就没有必要返回一个指向一个char*,刚刚返回的字符串(char * )就足够了。

  • 拟议API是比较合适的,如果功能是一个指针末端返回字符串,每行一个的阵列,具有一个额外的NULL,就像argv阵列作为第二个参数main传递功能。

对于这一点,你更多的行会从FILE*阅读并因为它的增长每一行应该被重新分配必须重新分配字符串数组。在字符串数组的末尾添加一个NULL指针以指示其结束。

这里是要做到这一点非常低效的方式:

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

char **format_file(FILE *infile) { 
     size_t lines = 0; 
     char **array = malloc(1 * sizeof(char*)); 
     size_t pos = 0; 
     char *line = malloc(1); 
     int c; 

     while ((c = getc(infile)) != EOF) { 
      if (c == '\n') { 
       line[pos] = '\0'; 
       array = realloc(array, (lines + 2) * sizeof(char *)); 
       array[lines++] = line; 
       line = malloc(1); 
       pos = 0; 
       continue; 
      } 
      line = realloc(line, pos + 2); 
      line[pos++] = c; 
    } 
    if (pos > 0) { 
     line[pos] = '\0'; 
     array = realloc(array, (lines + 2) * sizeof(char *)); 
     array[lines++] = line; 
    } else { 
     free(line); 
    } 
    array[lines] = NULL; 
    return array; 
} 
0

如果您只是创建一个字符数组,那么一维字符数组就足够了。不需要char**业务。但是,如果您尝试将它作为字符串使用,请确保您null终止数组。

+0

所以只需在最后添加'\ 0'? C不会自动执行此操作? –

+0

正确。 C一般不会为你做任何事情。一般的口头禅是“程序员永远是对的”,如果你不小心,会导致各种错误/分段错误。 – th13

+0

@ th13 C&C++的哲学是“程序员负责”,这就是C&C++如此有趣且具有挑战性的语言的原因。这就是为什么我不喜欢Java而不喜欢C#的原因。 – user7140484