分段错误:尝试打印包含 50k 项的数组时出现 11 返回程序C 示例使用fprintf()2个函数的完整测试

问题描述

我正在尝试将包含 50k 个项目的数组打印到文件中,但只有在我设置少量项目时才能完成,例如5k。

void fputsArray(int *arr,int size,char *filename)
{
    char *string = (char*)calloc( (8*size+1),sizeof(char) );
    for(int i = 0; i < size; i++)
        sprintf( &string[ strlen(string) ],"%d\n",arr[i] );

    FILE *output;
    char fullFilename[50] = "./";
    output = fopen(strcat(fullFilename,filename),"w");
    fputs(string,output);
    fclose(output);
    free(string);
}

size 是 50000,在 #DEFINE 中定义。 这是工作代码。但是如果我删除 8 乘以 size,那我应该工作,但不起作用。我遇到了这种情况分段错误:11 为什么我应该分配比我需要的多 8 倍的内存?

解决方法

假设您函数的输入都是正确的:

void fputsArray(int *arr,int size,char *filename)

尺寸应以 size_t 形式给出。

{
    char *string = (char*)calloc( (8*size+1),sizeof(char) );

不需要清除内存(calloc),malloc和设置string[0] = '\0'就足够了。 sizeof( char ) 根据定义始终为 1。还有you should not cast the result of an allocation

实际上,整个构造是不必要的,但那是以后用的。

    for(int i = 0; i < size; i++)
        sprintf( &string[ strlen(string) ],"%d\n",arr[i] );

实际上并没有那么糟糕,除了 string + strlen( string ) 更简单,并且语句周围应该始终有 { }。仍然不必要地复杂。

    FILE *output;
    char fullFilename[50] = "./";
    output = fopen(strcat(fullFilename,filename),"w");

文件名总是相对于当前工作目录,所以 "./" 是不必要的。但是,您应该检查文件名长度,然后strcat将它放入这样的静态缓冲区中。

    fputs(string,output);

啊,但是您还没有检查fopen 是否真的成功了!

    fclose(output);
    free(string);
}

总而言之,我见过更糟的。不过,您的数字是否真的适合您的缓冲区只是猜测,最重要的是整个记忆恶作剧是不必要的

考虑:

void printArray( int const * arr,size_t size,char const * filename )
{
    FILE * output = fopen( filename,"w" );
    if ( output != NULL )
    {
        for ( size_t i = 0; i < size; ++i )
        {
            fprintf( output,arr[i] );
        }
        fclose( output );
    }
    else
    {
        perror( "File open failed" );
    }
}

我认为这比试图找出您的记忆猜测出错的地方要好得多。


编辑:再想一想,我会让该函数采用 FILE * 参数而不是文件名,这将使您可以灵活地打印到已打开的流(例如stdout) 以及让您在更高的位置对 fopen 进行错误处理,该位置可能具有提供有用信息的附加功能。

,

大小为 50000,在#DEFINE 中定义。这是工作代码。但是如果我删除 8 乘以大小,那是我应该工作的,不起作用。我遇到了这种情况 Segmentation fault: 11 为什么我应该分配比我需要的内存多 8 倍的内存?

您正在撰写有关此尺寸估计的文章:

    char *string = (char*)calloc( (8*size+1),sizeof(char) );

但是正在使用的数组是 int[] 并且您将在磁盘中每行写入一个值

    sprintf( &string[ strlen(string) ],arr[i] );

这看起来不必要的复杂。至于大小,假设所有值都为INT_MIN,又名(在limits.h中)

#define INT_MIN     (-2147483647 - 1)

用于 4 字节整数。所以你有 11 个字符。只是。 10 位数字加一个符号表示信号。这将使您涵盖任何 int 值。为 '\n'

添加 1

但是……

  • 为什么要使用 calloc()?

  • 为什么不只使用一个 size * 12-byte 数组来拟合所有可能的值?

  • 为什么声明一个新的 char* 来保存 char 格式的值,而不是一次只使用 fprintf()

  • 为什么 void 而不是仅仅返回类似 -1 的错误或成功时写入磁盘的 itens 数量?

返回程序

如果您真的想在一次调用 fputs() 中将数组写入磁盘,将整个巨型字符串保存在内存中,请考虑 sprintf() 返回写入的字节数,所以这是您需要用作指向输出字符串的指针的值...

如果你想使用内存分配,你可以在块中进行。考虑到如果所有值都低于 999,则 50.000 行每行不会超过 4 个字节。但如果所有值都等于 INT_MIN,则每行最多 12 个字节。

因此,您可以使用 sprintf() 的返回值来更新指向字符串的指针,并在需要时使用 realloc(),以几个 K 字节的块为单位进行分配。 (如果你真的想回信,我可以贴一个例子)

C 示例

下面的代码按照您尝试的方式写入文件,并返回写入的总字节数。无论如何,这取决于数组的值。最大就是我说的,每行12个字节...

int fputsArray( unsigned size,int*  array,const char* filename)
{
    static char string[12 * MY_SIZE_ ] = {0};
    unsigned ix = 0; // pointer to the next char to use in string
    FILE*    output = fopen( filename,"w");
    if ( output == NULL ) return -1;
    // file is open
    for(int i = 0; i < size; i+= 1)
    {
        unsigned used = sprintf( (string + ix),array[i] );
        ix += used;
    } 
    fputs(string,output);
    fclose(output);
    return ix;
}

使用fprintf()

此代码使用 fprintf() 编写相同的文件,并且更简单...

int fputsArray_b( unsigned size,const char* filename)
{
    unsigned ix = 0; // bytes written
    FILE*    output = fopen( filename,"w");
    if ( output == NULL ) return -1;
    // file is open
    for(int i = 0; i < size; i+= 1)
        ix += fprintf( output,array[i]);
    fclose(output);
    return ix;
}

2个函数的完整测试

#define     MY_SIZE_ 50000
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>

int fputsArray(const unsigned,int*,const char*);
int fputsArray_b(const unsigned,const char*);

int main(void)
{
    int value[MY_SIZE_];
    srand(210726); // seed for today :)
    value[0] = INT_MIN; // just to test: this is the longest value
    for ( int  i=1; i<MY_SIZE_; i+=1 ) value[i] = rand();
    int used = fputsArray( MY_SIZE_,value,"test.txt");
    printf("%d bytes written to disk\n",used );

    used = fputsArray_b( MY_SIZE_,"test_b.txt");
    printf("%d bytes written to disk using the alternate function\n",used );
    return 0;
}


int fputsArray( unsigned size,output);
    fclose(output);
    return ix;
}

int fputsArray_b( unsigned size,array[i]);
    fclose(output);
    return ix;
}

程序写入 2 个相同的文件...

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...