如何在C中制作动态大小的数组?

我已经习惯了PHP,但我开始学习C.我正在尝试创建一个逐行读取文件并将每行存储到数组的程序。

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

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

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

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

要动态分配2D数组:

 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更新为前一个块。 您可以从开始单链表遍历并从一开始遍历或使用双链接。

C中没有标准的可resize的数组类型。您必须自己实现它,或使用第三方库。 这是一个简单的简单示例:

 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 )或不透明内存blob,这需要每个元素访问的转换和每个元素get / set的memcpy

无论如何,它并不漂亮。 二维arrays甚至更加丑陋。

如果您使用的是C,则需要自己实现数组的大小调整。 C ++和SDL为您完成了这项工作。 它被称为vectorhttp://www.cplusplus.com/reference/stl/vector/

您可以使用链接列表代替此处的数组,代码更简单,但分配更频繁,并且可能会受到碎片的影响。

只要你不打算做很多随机访问(这里是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; } 

虽然多维数组可以解决这个问题,但矩形2D数组并不是真正的C解决方案。

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

 #include  #include  #include  #include  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; } 

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

每次扩展时都需要手动跟踪数组大小。 一种常见的技术是每次扩展时将数组大小加倍,而不是按固定大小扩展; 这最大限度地减少了对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; }