二维阵列Malloc

二维阵列Malloc,c,C,下面是一段较长代码的一部分,其中对2D数组执行malloc'ing。谁能告诉我这是否正确?如果我引入静态值,代码工作正常。否则,分段故障 enum { LEN = 1024*8 }; char **tab = NULL; int cur_LEN = LEN; int count_lineMax = 0; tab = malloc(count_lineMax * sizeof(*tab)); memset(tab, 0, count_lineMax * sizeof(*tab))

下面是一段较长代码的一部分,其中对2D数组执行malloc'ing。谁能告诉我这是否正确?如果我引入静态值,代码工作正常。否则,分段故障

enum { LEN = 1024*8 };

char **tab = NULL;
int cur_LEN = LEN;
int count_lineMax = 0;


tab = malloc(count_lineMax * sizeof(*tab));
      memset(tab, 0, count_lineMax * sizeof(*tab));

if(tab == NULL && count_lineMax) {
    printf("Mem_check\n");
    exit(1);
}

for(k=0;k<count_lineMax;k++) {
    tab[k] = malloc(cur_LEN*sizeof(*tab[k]));
    memset(tab[k], 0, cur_LEN*sizeof(*tab[k]));

    if(tab[k] == NULL) {
        printf("Mem_check*\n");
        exit(1);
    }
}
for(l=0;l<count_lineMax;l++) {
    free(tab[l]);
}
free(tab);
enum{LEN=1024*8};
char**tab=NULL;
int cur_LEN=LEN;
int count_lineMax=0;
tab=malloc(count_lineMax*sizeof(*tab));
memset(tab,0,count_lineMax*sizeof(*tab));
if(tab==NULL&&count\u lineMax){
printf(“Mem_check\n”);
出口(1);
}
对于(k=0;k
这是什么?你要删除0个字节


这是什么?你要malloc 0字节?

至少有两种方法在读取行时构建表。一种方法使用
realloc()
的属性,即如果它的第一个参数是空指针,它的行为将类似于
malloc()
,并分配请求的空间(因此代码可以使用
realloc()自启动)
单独使用)。该代码可能如下所示:

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

enum { LEN = 1024*8 };

static void error(const char *fmt, ...);
static char *xstrdup(const char *str);

int main(void)
{
    char line[LEN];
    char **tab = NULL;
    int tabsize = 0;
    int lineno = 0;

    while (fgets(line, sizeof(line), stdin) != 0)
    {
        if (lineno >= tabsize)
        {
            size_t newsize = (tabsize + 2) * 2;
            char **newtab = realloc(tab, newsize * sizeof(*newtab));
            if (newtab == 0)
                error("Failed to allocate %zu bytes of memory\n", newsize * sizeof(*newtab));
            tab = newtab;
            tabsize = newsize;
        }
        tab[lineno++] = xstrdup(line);
    }

    /* Process the lines */
    for (int i = 0; i < lineno; i++)
        printf("%d: %s", i+1, tab[i]);

    /* Release the lines */
    for (int i = 0; i < lineno; i++)
        free(tab[i]);
    free(tab);

    return(0);
}

static void error(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    exit(1);
}

static char *xstrdup(const char *str)
{
    size_t len = strlen(str) + 1;
    char *copy = malloc(len);
    if (copy == 0)
        error("Failed to allocate %zu bytes of memory\n", len);
    memmove(copy, str, len);
    return(copy);
}
其他一切都可以保持不变

请注意,可以方便地使用函数
xmalloc()
xrealloc()
,它们保证不会返回空指针,因为它们会报告错误:

static void *xmalloc(size_t nbytes)
{
    void *space = malloc(nbytes);
    if (space == 0)
        error("Failed to allocate %zu bytes of memory\n", nbytes);
    return(space);
}

static void *xrealloc(void *buffer, size_t nbytes)
{
    void *space = realloc(buffer, nbytes);
    if (space == 0)
        error("Failed to reallocate %zu bytes of memory\n", nbytes);
    return(space);
}
从长远来看(大型程序),这会减少您写入“内存不足”错误消息的总次数。另一方面,如果您必须从内存分配失败中恢复(保存用户的工作等),则这不是一个合适的策略

上面的代码创建了一个参差不齐的数组;
tab
中的不同条目具有不同的长度。如果您想要相同的长度(如原始代码),则必须替换或修改
xstrdup()
函数以分配最大长度

您可能已经注意到,
xstrdup()
中的代码使用了
memmove()
而不是
strcpy()
。这是因为
strlen()
已经测量了字符串的长度,所以复制代码不需要测试每个字节是否需要复制
,因为它永远不会出错,即使字符串重叠,即使在这种情况下,很明显字符串永远不会重叠,因此
memcpy()
-如果字符串重叠,则不能保证正常工作-可以使用,因为字符串不能重叠

分配
(oldsize+2)*2
新条目的策略意味着在测试期间内存重新分配代码的执行频率足够高,不会对生产中的性能造成不适当的影响。有关这是一个好主意的原因,请参阅Kernighan和Pike的讨论


我几乎总是使用一组类似于
error()
函数的函数,因为它极大地简化了错误报告。我通常使用的函数是记录和报告程序名的包的一部分(来自
argv[0]
)同样,这也有相当广泛的替代行为。

在读取行时,至少有两种方法可以构建表。一种方法使用
realloc()
的属性,即如果其第一个参数是空指针,它的行为将类似于
malloc()
,并分配请求的空间(因此代码可以单独使用
realloc()
自启动)。该代码可能如下所示:

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

enum { LEN = 1024*8 };

static void error(const char *fmt, ...);
static char *xstrdup(const char *str);

int main(void)
{
    char line[LEN];
    char **tab = NULL;
    int tabsize = 0;
    int lineno = 0;

    while (fgets(line, sizeof(line), stdin) != 0)
    {
        if (lineno >= tabsize)
        {
            size_t newsize = (tabsize + 2) * 2;
            char **newtab = realloc(tab, newsize * sizeof(*newtab));
            if (newtab == 0)
                error("Failed to allocate %zu bytes of memory\n", newsize * sizeof(*newtab));
            tab = newtab;
            tabsize = newsize;
        }
        tab[lineno++] = xstrdup(line);
    }

    /* Process the lines */
    for (int i = 0; i < lineno; i++)
        printf("%d: %s", i+1, tab[i]);

    /* Release the lines */
    for (int i = 0; i < lineno; i++)
        free(tab[i]);
    free(tab);

    return(0);
}

static void error(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    exit(1);
}

static char *xstrdup(const char *str)
{
    size_t len = strlen(str) + 1;
    char *copy = malloc(len);
    if (copy == 0)
        error("Failed to allocate %zu bytes of memory\n", len);
    memmove(copy, str, len);
    return(copy);
}
其他一切都可以保持不变

请注意,可以方便地使用函数
xmalloc()
xrealloc()
,它们保证不会返回空指针,因为它们会报告错误:

static void *xmalloc(size_t nbytes)
{
    void *space = malloc(nbytes);
    if (space == 0)
        error("Failed to allocate %zu bytes of memory\n", nbytes);
    return(space);
}

static void *xrealloc(void *buffer, size_t nbytes)
{
    void *space = realloc(buffer, nbytes);
    if (space == 0)
        error("Failed to reallocate %zu bytes of memory\n", nbytes);
    return(space);
}
从长远来看(大型程序),这会减少您写入“内存不足”错误消息的总次数。另一方面,如果您必须从内存分配失败中恢复(保存用户的工作等),则这不是一个合适的策略

上面的代码创建了一个参差不齐的数组;
tab
中的不同条目具有不同的长度。如果您想要相同的长度(如原始代码),则必须替换或修改
xstrdup()
函数以分配最大长度

您可能已经注意到,
xstrdup()
中的代码使用了
memmove()
而不是
strcpy()
。这是因为
strlen()
已经测量了字符串的长度,所以复制代码不需要测试每个字节是否需要复制,因为它永远不会出错,即使字符串重叠,即使在这种情况下,很明显字符串永远不会重叠,因此
memcpy()
-如果字符串重叠,则不能保证正常工作-可以使用,因为字符串不能重叠

分配
(oldsize+2)*2
新条目的策略意味着在测试期间内存重新分配代码的执行频率足够高,不会对生产中的性能造成不适当的影响。有关这是一个好主意的原因,请参阅Kernighan和Pike的讨论


我几乎总是使用一组类似于
error()
函数的函数,因为它极大地简化了错误报告。我通常使用的函数是记录和报告程序名的包的一部分(来自
argv[0]
)同样,这也有相当广泛的替代行为。

count\u lineMax为零,因此您不分配任何内容。看起来还可以;即使在设置count\u lineMax时也适用于我。您已经说过可以分配单个块。由于分配了0个字节而未进行检查,因此您会遇到seg错误(malloc每次都将返回null)。如果您确实想要一个2D数组,您可以在一行中一次性分配整个块。如果您想要一个可变长度C字符串数组(这是您想要的),您需要使用lineMax>0对第一个列表进行malloc,然后在每个元素处为该位置的可变长度C字符串分配足够的空间(不要忘记为“\0”包含一个额外的字符),您需要检查内存分配