如何创建字符串数组?

时间:2016-02-16 05:36:29

标签: c arrays multidimensional-array dynamic-memory-allocation

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

我查看了其他similar questions,他们要么修复整个事物,要么动态分配。你怎么能两个都做?

char A[malloc][100];

我的猜测是:

char *A[100];

1 个答案:

答案 0 :(得分:2)

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

注意下面xcalloc只是calloc的包装器,它为每一行分配空间并进行错误检查。下面的分配是长期的(注意:您可以用注释中指示的strdup替换长路)完整的allocate / validate / nul-terminate分配方法如下所示,例如/说明。

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

#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

使用/输出

$ ./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.

内存泄漏/错误检查

在你的动态分配内存的任何代码中,你有2个责任关于任何分配的内存块:(1)总是保留一个指向内存块起始地址的指针,所以,(2)它可以在释放时释放它不再需要了。您必须使用内存错误检查程序,以确保您没有在已分配的内存块之外/之外写入,并确认已释放已分配的所有内存。对于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)