2011-08-28 111 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; 
} 
相關問題