分段错误:尝试打印包含 50k 项的数组时出现 11
Segmentation fault: 11 while trying to print array with 50k items
我正在尝试将包含 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] = '[=20=]'
即可。根据定义,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, "%d\n", arr[i] );
}
fclose( output );
}
else
{
perror( "File open failed" );
}
}
我认为这 比试图弄清楚你的记忆猜测哪里出了问题要好得多。
编辑: 转念一想,我想让那个函数接受一个 FILE *
参数而不是文件名,这样你就可以灵活地打印到一个已经-打开流(如 stdout
),并且还允许您在更高的位置进行 fopen
的错误处理,该位置可能具有提供有用信息的附加功能。
size is 50000, defined in #DEFINE. This is working code. But if I delete 8 multiplying to size, that is I supposed to be working, doesn't work. I got in that situation Segmentation fault: 11 Why should I allocate 8 times more memory than I need?
你写的是这个尺寸估计值:
char *string = (char*)calloc( (8*size+1), sizeof(char) );
但是正在使用的数组是 int[]
并且您将在磁盘中每行写入一个值,如
sprintf( &string[ strlen(string) ], "%d\n", arr[i] );
这个好像没必要复杂。至于大小,假设所有值都为INT_MIN
、a.k.a。 (在 limits.h
)
#define INT_MIN (-2147483647 - 1)
对于 4 字节整数。所以你有 11 个字符。只是。 10 位数字加一个符号作为信号。这将使您涵盖任何 int
值。 '\n'
加1
但是...
为什么要使用 calloc()?
为什么不直接使用适合所有可能值的 size * 12-byte
数组?
为什么要声明一个新的 char*
来保存 char
格式的值而不是立即使用 fprintf()
?
为什么 void
而不是 return 为错误输入类似 -1 的东西或在成功时写入磁盘的 itens 数量?
返回程序
如果您真的想在对 fputs()
的一次调用中将数组写入磁盘,将整个巨大的字符串保存在内存中,请考虑 sprintf()
returns 数字写入的字节数,所以这是您需要用作指向输出字符串的指针的值...
如果你想使用内存分配,你可以分块进行。考虑到如果所有值都小于 999,则 50.000 行每行将不超过 4 个字节。但是,如果所有值都等于 INT_MIN
,则每行最多 12 个字节。
所以你可以使用 sprintf()
的 return 来更新指向字符串的指针,并在需要时使用 realloc()
,比方说,以几 K 的块为单位进行分配-字节。 (如果你真的想回信,我可以 post 举个例子)
C 示例
下面的代码按照您尝试的方式写入文件,returns 写入的总字节数。无论如何,这取决于数组的值。最大就是我说的,每行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), "%d\n", array[i] );
ix += used;
}
fputs(string, output);
fclose(output);
return ix;
}
使用fprintf()
此代码使用 fprintf()
编写相同的文件,并且更简单...
int fputsArray_b( unsigned size, int* array , 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, "%d\n", 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,int*,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_, value, "test_b.txt");
printf("%d bytes written to disk using the alternate function\n", used );
return 0;
}
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), "%d\n", array[i] );
ix += used;
}
fputs(string, output);
fclose(output);
return ix;
}
int fputsArray_b( unsigned size, int* array , 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, "%d\n", array[i]);
fclose(output);
return ix;
}
程序写入了 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] = '[=20=]'
即可。根据定义,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, "%d\n", arr[i] );
}
fclose( output );
}
else
{
perror( "File open failed" );
}
}
我认为这 比试图弄清楚你的记忆猜测哪里出了问题要好得多。
编辑: 转念一想,我想让那个函数接受一个 FILE *
参数而不是文件名,这样你就可以灵活地打印到一个已经-打开流(如 stdout
),并且还允许您在更高的位置进行 fopen
的错误处理,该位置可能具有提供有用信息的附加功能。
size is 50000, defined in #DEFINE. This is working code. But if I delete 8 multiplying to size, that is I supposed to be working, doesn't work. I got in that situation Segmentation fault: 11 Why should I allocate 8 times more memory than I need?
你写的是这个尺寸估计值:
char *string = (char*)calloc( (8*size+1), sizeof(char) );
但是正在使用的数组是 int[]
并且您将在磁盘中每行写入一个值,如
sprintf( &string[ strlen(string) ], "%d\n", arr[i] );
这个好像没必要复杂。至于大小,假设所有值都为INT_MIN
、a.k.a。 (在 limits.h
)
#define INT_MIN (-2147483647 - 1)
对于 4 字节整数。所以你有 11 个字符。只是。 10 位数字加一个符号作为信号。这将使您涵盖任何 int
值。 '\n'
但是...
为什么要使用 calloc()?
为什么不直接使用适合所有可能值的
size * 12-byte
数组?为什么要声明一个新的
char*
来保存char
格式的值而不是立即使用fprintf()
?为什么
void
而不是 return 为错误输入类似 -1 的东西或在成功时写入磁盘的 itens 数量?
返回程序
如果您真的想在对 fputs()
的一次调用中将数组写入磁盘,将整个巨大的字符串保存在内存中,请考虑 sprintf()
returns 数字写入的字节数,所以这是您需要用作指向输出字符串的指针的值...
如果你想使用内存分配,你可以分块进行。考虑到如果所有值都小于 999,则 50.000 行每行将不超过 4 个字节。但是,如果所有值都等于 INT_MIN
,则每行最多 12 个字节。
所以你可以使用 sprintf()
的 return 来更新指向字符串的指针,并在需要时使用 realloc()
,比方说,以几 K 的块为单位进行分配-字节。 (如果你真的想回信,我可以 post 举个例子)
C 示例
下面的代码按照您尝试的方式写入文件,returns 写入的总字节数。无论如何,这取决于数组的值。最大就是我说的,每行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), "%d\n", array[i] );
ix += used;
}
fputs(string, output);
fclose(output);
return ix;
}
使用fprintf()
此代码使用 fprintf()
编写相同的文件,并且更简单...
int fputsArray_b( unsigned size, int* array , 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, "%d\n", 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,int*,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_, value, "test_b.txt");
printf("%d bytes written to disk using the alternate function\n", used );
return 0;
}
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), "%d\n", array[i] );
ix += used;
}
fputs(string, output);
fclose(output);
return ix;
}
int fputsArray_b( unsigned size, int* array , 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, "%d\n", array[i]);
fclose(output);
return ix;
}
程序写入了 2 个相同的文件...