【问题标题】:Inserting into a dynamic character array while using realloc()使用 realloc() 插入动态字符数组
【发布时间】:2020-09-27 22:04:24
【问题描述】:

我非常想追上我的 C 编程技能,所以我开始了自己的自学计划,尝试读取文件并将其内容插入不同的数据结构。

在这里,我想专门使用一个动态分配的指针数组。我已经在另一个类似的程序中成功使用了getc(),但是通过使用静态数组,所以我非常想在这里继续使用getc()函数。

所以在这个新的实现中,在这里,我只是想将输入文件中的所有字符插入到一个数组中,该数组是我使用malloc() 分配的。一次读取一个字符后,我试图每次将这个指针数组的大小调整为一个字符的大小,以便在下一次迭代中有下一个字符的空间。然后,之后,通过新的指针数组[逐个字符]迭代并简单地打印出所有内容。

但是,我收到了分段错误,所以也许我做的有点不对?非常感谢任何反馈。

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

void main( int argc, char *argv[] )
{

    FILE *filePointer;
    int c, i;
    char *input_arrayPointer;
    input_arrayPointer = ( char* ) calloc ( 1, sizeof( char ) );
    printf("%p\n", input_arrayPointer);
    int filled_elements = 0;
    filePointer = fopen( argv[1], "r" );

    if ( argc > 2 )
    {
        printf( "\nIncorrect usage, please say...\nRunProgram *filename*\n\n" );
        exit( 1 );
    }

    if ( filePointer != NULL )
    {   
        while ( ( c = getc( filePointer ) ) != EOF )
        {
            // filled_elements, to start, is 0

            *( input_arrayPointer + filled_elements ) = c;
            filled_elements++;
            input_arrayPointer = ( char* ) realloc ( input_arrayPointer, (filled_elements * sizeof( char ) ) );
        }
    }

    fclose( filePointer );

    for ( i = 0; i < filled_elements; i++, input_arrayPointer++ )
    {
        printf("%c", *( input_arrayPointer + filled_elements );
    }
}

【问题讨论】:

    标签: c segmentation-fault malloc realloc getc


    【解决方案1】:

    while ( ( c = getc( filePointer ) ) != EOF )
    {
        // filled_elements, to start, is 0
    
        *( input_arrayPointer + filled_elements ) = c;
        filled_elements++;
        input_arrayPointer = ( char* ) realloc ( input_arrayPointer, (filled_elements * sizeof( char ) ) );
    }
    

    第一次迭代会发生什么?

    1. input_arrayPointer 大一字节
    2. filled_elements 为 0
    3. input_arrayPointer 的第一个字节被写入
    4. filled_elements 递增
    5. realloc 被调用为filled_elements 字节......那是 1!!!没有数组大小增量!
    6. 第二个字符被写入非法地址(动态分配区域外)

    你只需要多分配一个字节

    input_arrayPointer = ( char* ) realloc ( input_arrayPointer, ((filled_elements+1) * sizeof( char ) ) );
    

    更好:始终检查realloc 返回值。并使用临时指针避免丢失原始指针以防万一失败。
    realloc 什么时候失败?当它没有成功分配请求的大小时。在这种情况下,如man page 中所述,NULL 将被返回并分配给input_arrayPointer。这不是你想要的。
    这样可以避免这个问题:

    char *temp = realloc ( input_arrayPointer, ((filled_elements+1) * sizeof( char ) ) );
    if (temp != NULL)
    {
        input_arrayPointer = temp;
    }
    

    注意: realloc 不保证扩展原始指针,因为它必须找到一个足够宽的连续内存范围以包含请求的大小。相反,它会找到新的内存区域并将指针的原始内容复制到那里(如果是 newSize &gt; oldSize,则全部复制;否则为 newSize 字节)。

    【讨论】:

    • 您的回复表明并使用临时指针来避免在这种情况下丢失原始指针....。据我了解,realloc 将保留内存块并根据请求进行扩展。 Dynamic Memory Allocation in C using malloc(), calloc(), free() and realloc()。你能详细说说你的想法吗?
    • @MahendraGunawardena 不幸的是,您的理解是错误的。可以想象,有几种方法可以实现堆内存,但它们都不能在malloc 返回的每个堆区域之后保留未定义的字节数,以防万一需要realloc。 :) 因此,在原始指针指向的区域之后,通常会有另一个由 malloc 分配给另一个指针的区域。 [继续]
    • @MahendraGunawardena 正如manual 中所解释的,保证 “内容将在从区域开始到旧区域的最小值的范围内保持不变新尺寸。” 我修改了我的答案,添加了一个带有此解释的注释,并改进了您引用的建议,解释了realloc 失败时会发生什么(返回 NULL)。
    • 感谢您的回复和详细说明。所以我之前评论的附加链接中对realloc的解释具有误导性。
    • @MahendraGunawardena 实际上并非如此:它声明“realloc 可用于动态重新分配内存。重新分配内存保持现有值和新块将使用默认垃圾值进行初始化。”_ 所以它确认 values*(又名 **contents)被保留。它没有提到存储数据的内存位置也被保留。
    猜你喜欢
    • 2016-08-12
    • 2013-02-11
    • 2021-04-07
    • 1970-01-01
    • 2015-02-13
    • 1970-01-01
    • 2019-01-10
    • 2011-10-19
    • 2021-03-12
    相关资源
    最近更新 更多