2011-08-28 72 views
9

我习惯于PHP,但我开始学习C.我试图创建一个程序,逐行读取文件并将每行存储到数组中。如何在C中创建动态大小的数组?

到目前为止,我有一个程序逐行读取文件,甚至打印每一行,但现在我只需要将每行添加到数组。

昨天晚上我的朋友告诉了我一些关于它的信息。他说我不得不在C中使用多维数组,所以基本上array[x][y][y]部分本身很容易,因为我知道每行的最大字节数。但是,我不知道该文件将有多少个

我想我可以通过文件循环,每次只增加一个整数并使用它,但我觉得可能有一个更简单的方法。

任何想法或甚至暗示正确的方向?我感谢任何帮助。

+0

可以使用函数'realloc'稍后改变所述阵列的大小。 – Jonathon

+0

我会去查看该功能,并尝试考虑如何实现它,我会尽快回复给您,谢谢 – Rob

回答

9

为了动态分配的二维数组:

char **p; 
int i, dim1, dim2; 


/* Allocate the first dimension, which is actually a pointer to pointer to char */ 
p = malloc (sizeof (char *) * dim1); 

/* Then allocate each of the pointers allocated in previous step arrays of pointer to chars 
* within each of these arrays are chars 
*/ 
for (i = 0; i < dim1; i++) 
    { 
    *(p + i) = malloc (sizeof (char) * dim2); 
    /* or p[i] = malloc (sizeof (char) * dim2); */ 
    } 

/* Do work */ 

/* Deallocate the allocated array. Start deallocation from the lowest level. 
* that is in the reverse order of which we did the allocation 
*/ 
for (i = 0; i < dim1; i++) 
{ 
    free (p[i]); 
} 
free (p); 

修改上述方法。当您需要添加另一条线时,请执行*(p + i) = malloc (sizeof (char) * dim2);并更新i。在这种情况下,您需要预测文件中由dim1变量指示的最大行数,我们首次为其分配p数组。这将只分配(sizeof (int *) * dim1)字节,因此比char p[dim1][dim2](在c99中)要好得多。

我还有另外一种方式。在块中分配数组并在出现溢出时将其链接起来。

struct _lines { 
    char **line; 
    int n; 
    struct _lines *next; 
} *file; 

file = malloc (sizeof (struct _lines)); 
file->line = malloc (sizeof (char *) * LINE_MAX); 
file->n = 0; 
head = file; 

在此之后的第一个块就可以使用了。当你需要插入线只是做:

/* get line into buffer */ 
file.line[n] = malloc (sizeof (char) * (strlen (buffer) + 1)); 
n++; 

nLINE_MAX分配另一个块,并将其链接到了这里。

struct _lines *temp; 

temp = malloc (sizeof (struct _lines)); 
temp->line = malloc (sizeof (char *) * LINE_MAX); 
temp->n = 0; 
file->next = temp; 
file = file->next; 

就像这样。

当一个块的n变为0时,将其解除分配,并将当前块指针file更新为上一个块。您可以从单个链表开始遍历并从头开始遍历或使用双链接。

+0

后一种方法是当输入文件不可查找(如管道或stdin)时,GNU的“tail(1)”实现如何工作。由于在这种情况下只能通过输入文件一次,因此它将文件存储在内存块的链接列表中,当文件达到文件结束时,它会向后搜索以打印出最后一个“N”行。 –

+0

@Adam Rosenfield:不知道,谢谢你提供的信息。我用它在很久以前在内存中存储了一长串单词,它非常有用。 – phoxis

5

C中没有标准的可调整大小的数组类型。您必须自己实现它,或使用第三方库。这里有一个简单的裸机例如:

typedef struct int_array 
{ 
    int *array; 
    size_t length; 
    size_t capacity; 
} int_array; 

void int_array_init(int_array *array) 
{ 
    array->array = NULL; 
    array->length = 0; 
    array->capacity = 0; 
} 

void int_array_free(int_array *array) 
{ 
    free(array->array); 
    array->array = NULL; 
    array->length = 0; 
    array->capacity = 0; 
} 

void int_array_push_back(int_array *array, int value) 
{ 
    if(array->length == array->capacity) 
    { 
     // Not enough space, reallocate. Also, watch out for overflow. 
     int new_capacity = array->capacity * 2; 
     if(new_capacity > array->capacity && new_capacity < SIZE_T_MAX/sizeof(int)) 
     { 
      int *new_array = realloc(array->array, new_capacity * sizeof(int)); 
      if(new_array != NULL) 
      { 
       array->array = new_array; 
       array->capacity = new_capacity; 
      } 
      else 
       ; // Handle out-of-memory 
     } 
     else 
      ; // Handle overflow error 
    } 

    // Now that we have space, add the value to the array 
    array->array[array->length] = value; 
    array->length++; 
} 

使用方法如下:

int_array a; 
int_array_init(&a); 

int i; 
for(i = 0; i < 10; i++) 
    int_array_push_back(&a, i); 
for(i = 0; i < a.length; i++) 
    printf("a[%d] = %d\n", i, a.array[i]); 

int_array_free(&a); 

当然,这仅仅是为了int秒的阵列。由于C没有模板,因此您必须将所有这些代码放入每个不同类型数组的宏(或使用其他预处理器,如GNU m4)。或者,您可以使用通用数组容器,该容器使用void*指针(要求所有数组元素为malloc'ed)或不透明内存blob,这需要在每个元素都可以访问的情况下进行强制转换,并且每个元素都需要使用memcpy

无论如何,这并不美丽。二维数组甚至更丑陋。

0

而不是在这里的数组,你也可以使用链表,代码更简单,但分配更频繁,可能会遭受碎片化。

只要你不打算做很多随机访问(这里是O(n)),迭代就像普通数组一样简单。

typedef struct Line Line; 
struct Line{ 
    char text[LINE_MAX]; 
    Line *next; 
}; 

Line *mkline() 
{ 
    Line *l = malloc(sizeof(Line)); 
    if(!l) 
     error(); 
    return l; 
} 

main() 
{ 
    Line *lines = mkline(); 
    Line *lp = lines; 
    while(fgets(lp->text, sizeof lp->text, stdin)!=NULL){ 
     lp->next = mkline(); 
     lp = lp->next; 
    } 
    lp->next = NULL; 
} 
0

虽然一个多维数组可以解决这个问题,矩形2D阵列不会真的是自然℃溶液。

这是一个程序,最初将文件读入链表中,然后分配一个正确大小的指针向量。每个单独的字符然后显示为array[line][col],但实际上每行只有它需要的时间。它的C99除了<err.h>

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

typedef struct strnode { 
    char *s; 
    struct strnode *next; 
} strnode; 

strnode *list_head; 
strnode *list_last; 

strnode *read1line(void) { 
    char space[1024]; 
    if(fgets(space, sizeof space, stdin) == NULL) 
    return NULL; 
    strnode *node = malloc(sizeof(strnode)); 
    if(node && (node->s = malloc(strlen(space) + 1))) { 
    strcpy(node->s, space); 
    node->next = NULL; 
    if (list_head == NULL) 
     list_head = node; 
    else 
     list_last->next = node; 
    list_last = node; 
    return node; 
    } 
    err(1, NULL); 
} 

int main(int ac, char **av) { 
    int n; 
    strnode *s; 

    for(n = 0; (s = read1line()) != NULL; ++n) 
    continue; 
    if(n > 0) { 
    int i; 
    strnode *b; 
    char **a = malloc(n * sizeof(char *)); 
    printf("There were %d lines\n", n); 
    for(b = list_head, i = 0; b; b = b->next, ++i) 
     a[i] = b->s; 
    printf("Near the middle is: %s", a[n/2]); 
    } 
    return 0; 
} 
0

可以使用mallocrealloc函数来动态地分配和调整大小指针数组以char,并且阵列中的每个元素将指向从文件(其中该字符串的存储也被分配读取的字符串动态)。为了简单起见,我们假设每行的最大长度小于M个字符(计算换行符),所以我们不必对个别行进行任何动态调整。

您需要在每次扩展时手动跟踪数组大小。常用的技术是每次扩展时将数组大小加倍,而不是按固定大小扩展;这最大限度地减少了对realloc的呼叫数量,这可能是昂贵的。当然这意味着你必须跟踪两个数量;数组的总大小和当前读取的元素的数量。

实施例:

#define INITIAL_SIZE ... // some size large enough to cover most cases 

char **loadFile(FILE *stream, size_t *linesRead) 
{ 
    size_t arraySize = 0; 
    char **lines = NULL; 
    char *nextLine = NULL; 

    *linesRead = 0; 

    lines = malloc(INITIAL_SIZE * sizeof *lines); 
    if (!lines) 
    { 
    fprintf(stderr, "Could not allocate array\n"); 
    return NULL; 
    } 

    arraySize = INITIAL_SIZE; 

    /** 
    * Read the next input line from the stream. We're abstracting this 
    * out to keep the code simple. 
    */ 
    while ((nextLine = getNextLine(stream))) 
    { 
    if (arraySize <= *linesRead) 
    { 
     char **tmp = realloc(lines, arraysSize * 2 * sizeof *tmp); 
     if (tmp) 
     { 
     lines = tmp; 
     arraySize *= 2; 
     } 
    } 
    lines[(*linesRead)++] = nextLine; 
) 

    return lines; 
} 
相关问题