如何创建字符串数组?

How do I create an array of strings?

我需要创建一个数组 I,其中列数组是固定大小,行数组是动态分配的(使用 malloc)。

我查看了其他 similar questions,他们将整个内容固定或动态分配。你怎么能两者兼得?

char A[malloc][100];

我的猜测是:

char *A[100];

根据我的评论,您可以静态声明一个指针数组,然后为从文件中读取的每一行动态分配存储空间。下面是一个展示这种方法的简短例子。您必须保留读取行数的索引或计数器,以防止写入超出指针数组的末尾。

注意下面的 xcalloc 只是 calloc 的包装器,它为每一行分配 space 并进行错误检查。下面的分配是长途(注意:您可以用 strdup 替换长途,如评论中所示)完整的 allocate/validate/nul-terminate 分配方法如下所示 example/explanation。

您可以通过更改 #define MAXL 值来更改声明的指针数,并通过更改 #define MAXC 值来调整每行的最大字符数。查看并了解每行的每个部分在做什么。请注意静态缓冲区 buf 的使用,在分配内存之前将初始行读入其中,并将内容分配给数组中的索引。这非常有用,因为它允许您在为其分配 space 并将字符串复制到新内存之前验证您所阅读的内容。它允许您跳过空行等,这比 free/unindex 不需要的行要简单得多:

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

#define MAXC 256    /* max chars per-line   */
#define MAXL 100    /* initial num pointers */

void *xcalloc (size_t n, size_t s);

int main (int argc, char **argv) {

    char *array[MAXL] = {NULL};
    char buf[MAXC] = {0};
    size_t i, idx = 0;
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    while (fgets (buf, MAXC, fp))  /* read all lines from fp into array */
    {
        size_t len = strlen (buf);

        /* validate complete line read */
        if (len + 1 == MAXC && buf[len - 1] != '\n')
            fprintf (stderr, "warning: line[%zu] exceeded '%d' chars.\n",
                    idx, MAXC);

        /* strip trailing '\r', '\n' */
        while (len && (buf[len-1] == '\n' || buf[len-1] == '\r'))
            buf[--len] = 0;

        /* allocate & copy buf to array[idx], nul-terminate
         * note: this can all be done with array[idx] = strdup (buf);
         */
        array[idx] = xcalloc (len + 1, sizeof **array);
        strncpy (array[idx], buf, len);
        array[idx++][len] = 0;

        /* MAXL limit check - if reached, break */
        if (idx == MAXL) break;
    }
    if (fp != stdin) fclose (fp);

    printf ("\n lines read from '%s'\n\n", argc > 1 ? argv[1] : "stdin");
    for (i = 0; i < idx; i++)
        printf ("   line[%3zu]  %s\n", i, array[i]);

    for (i = 0; i < idx; i++)
        free (array[i]);    /* free each line */

    return 0;
}

/* simple calloc with error checking */
void *xcalloc (size_t n, size_t s)
{
    void *memptr = calloc (n, s);
    if (memptr == 0) {
        fprintf (stderr, "xcalloc() error: virtual memory exhausted.\n");
        exit (EXIT_FAILURE);
    }

    return memptr;
}

编译

gcc -Wall -Wextra -O3 -o bin/fgets_lines_stat_dyn fgets_lines_stat_dyn.c

Use/Output

$ ./bin/fgets_lines_stat_dyn dat/captnjack.txt

 lines read from 'dat/captnjack.txt'

   line[  0]  This is a tale
   line[  1]  Of Captain Jack Sparrow
   line[  2]  A Pirate So Brave
   line[  3]  On the Seven Seas.

内存Leak/Error检查

在您编写的任何动态分配内存的代码中,您对分配的任何内存块负有 2 个责任:(1) 始终保留指向内存块起始地址的指针,因此,(2) 它可以是不再需要时释放。您必须使用内存错误检查程序来确保您没有写入 beyond/outside 您分配的内存块并确认您已释放所有分配的内存。对于 Linux valgrind 是正常的选择。滥用内存块的微妙方法有很多,可能会导致真正的问题,没有理由不这样做。每个平台都有类似的内存检查器。它们都易于使用。只是运行你的程序通过它。

$ valgrind ./bin/fgets_lines_stat_dyn dat/captnjack.txt
==22770== Memcheck, a memory error detector
==22770== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==22770== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==22770== Command: ./bin/fgets_lines_dyn dat/captnjack.txt
==22770==

 lines read from 'dat/captnjack.txt'

   line[  0]  This is a tale
   line[  1]  Of Captain Jack Sparrow
   line[  2]  A Pirate So Brave
   line[  3]  On the Seven Seas.
==22770==
==22770== HEAP SUMMARY:
==22770==     in use at exit: 0 bytes in 0 blocks
==22770==   total heap usage: 6 allocs, 6 frees, 1,156 bytes allocated
==22770==
==22770== All heap blocks were freed -- no leaks are possible
==22770==
==22770== For counts of detected and suppressed errors, rerun with: -v
==22770== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)