为什么每次尝试将元素存储到 C 中的数组时都会出现段错误?
Why am I getting a seg fault every time I try to store elements into an array in C?
所以,我正在尝试从文件中读取矩阵并将其存储到数组中。
矩阵文件如下:
2 3
1 5 8
6 3 9
第一行的前两位数字代表行 x 列。
每当我尝试将某些内容存储到数组中时,我似乎都会遇到问题,因为我能够简单地将所有内容重新打印到屏幕上,但每当我尝试添加到数组中时,我都会遇到段错误。
我的代码如下:
double *read_matrix(char *filename){
FILE *file=fopen(filename, "r");
if(!file){
fprintf(stderr, "An error has occurred. Wrong file name?\n");
exit(errno);
}
double *data=(double *)malloc(sizeof(double)*4096);
char *buff=malloc(sizeof(char *)*256);
char *curr;
while(fgets(buff,sizeof(buff),file)){
curr=strtok_r(buff," ",&buff);
int i=0;
while(curr!=NULL){
curr=strtok_r(NULL," ",&buff);
data[i]=strtod(curr,NULL); //this
i++;
}
}
return data;
}
每当我使用 GDB 进行调试并使用 backtrace 命令时,它都会将我带到注释行 //this
。
我无法理解我做错了什么,我开始发疯了!
您需要在相关行之前检查 strtok_r
中的 return 值。
您在调用 strtod()
之前没有检查 curr
的值。
这个:
(...)
while(curr!=NULL){
curr=strtok_r(NULL," ",&buff);
data[i]=strtod(curr,NULL); //this
i++;
}
应该是:
(...)
while(1){
curr=strtok_r(NULL," ",&buff);
if (curr == NULL)
break;
data[i]=strtod(curr,NULL); //this
i++;
}
这个
while(curr!=NULL){
curr=strtok_r(NULL," ",&buff);
data[i]=strtod(curr,NULL); //this
i++;
}
应该是
while(curr!=NULL){
data[i]=strtod(curr,NULL); //this
i++;
curr=strtok_r(NULL," ",&buff); // Looking for next token shall
// be the last statement
}
进一步这条线
char *buff=malloc(sizeof(char *)*256);
错了。应该是
char *buff=malloc(sizeof(char)*256);
^^^^
No *
但一般来说 malloc
最好使用以下形式:
double *data = malloc(4096 * sizeof *data);
^^^^^^^^^^^^
char *buff=malloc(256 * sizeof *buff);
^^^^^^^^^^^^
通过使用 sizeof *varname
,您可以避免简单的类型不匹配。
在你的情况下,你甚至不需要使用 strtok。只需使用管理空白的 strtod :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
double *read_matrix(char *filename){
FILE *file=fopen(filename, "r");
if(!file){
fprintf(stderr, "An error has occurred. Wrong file name?\n");
exit(1);
}
double *data = malloc(10 * sizeof(double));
char *buff = malloc(10 * sizeof(char));
char *end_pointer;
char *newline_pos;
int i = 0;
while(fgets(buff,sizeof(buff),file)){
//removing newline character read by fgets
if ((newline_pos = strchr(buff, '\n')) != NULL) {
*newline_pos = '[=10=]';
}
while (strlen(buff) != 0) {
data[i] = strtod(buff,&end_pointer);
buff = end_pointer;
i++;
}
}
//convenient for printf output
data[i] = '[=10=]';
return data;
}
int main(void) {
char file[] = "matrix.txt";
double *array = read_matrix(file);
int i = 0;
while (array[i] != '[=10=]') {
printf("%f ",array[i]);
i++;
}
printf("\n");
}
您的代码中有多个问题未在其他答案中解决:
double *read_matrix(char *filename){
FILE *file=fopen(filename, "r");
if(!file){
fprintf(stderr, "An error has occurred. Wrong file name?\n");
exit(errno);
}
double *data=(double *)malloc(sizeof(double)*4096);
char *buff=malloc(sizeof(char *)*256);
您需要一个字符缓冲区,而不是指针缓冲区。
char *curr;
while(fgets(buff,sizeof(buff),file)){
sizeof
不会评估缓冲区的大小,而只会评估 char*
的大小,在大多数系统上为 4 或 8。这可能不足以构成完整的一行。
curr=strtok_r(buff," ",&buff);
您正在循环内修改 buff
。当您在循环的下一次迭代中将它用于 fgets
时,您将不会使用从 malloc
.
获得的地址
int i=0;
您将读取的每一行的数组索引设置为 0。最后这只会保留最后一行的值。
while(curr!=NULL){
curr=strtok_r(NULL," ",&buff);
data[i]=strtod(curr,NULL); //this
i++;
}
}
return data;
这只包含最后一行的数字,甚至只包含最后一行前 8 个字节中的数字。
来电者怎么知道你读了多少号码?
}
固定的解决方案可能如下所示:
#define BUFFSIZE 256
double *read_matrix(char *filename, int *numread) {
FILE *file=fopen(filename, "r");
if(!file){
fprintf(stderr, "An error has occurred. Wrong file name?\n");
exit(errno);
}
double *data = malloc(sizeof(double)*4096);
char *buff = malloc(BUFFSIZE);
char *curr = NULL;
char *savetr = NULL;
int i = 0;
while (fgets(buff, BUFFSIZE, file)){
curr = strtok_r(buff, " ", &saveptr);
while(curr != NULL){
data[i] = strtod(curr, NULL);
i++;
curr=strtok_r(NULL, " ", &saveptr);
}
}
if (numread != NULL)
*numread=i;
return data;
}
所以,我正在尝试从文件中读取矩阵并将其存储到数组中。
矩阵文件如下:
2 3
1 5 8
6 3 9
第一行的前两位数字代表行 x 列。
每当我尝试将某些内容存储到数组中时,我似乎都会遇到问题,因为我能够简单地将所有内容重新打印到屏幕上,但每当我尝试添加到数组中时,我都会遇到段错误。
我的代码如下:
double *read_matrix(char *filename){
FILE *file=fopen(filename, "r");
if(!file){
fprintf(stderr, "An error has occurred. Wrong file name?\n");
exit(errno);
}
double *data=(double *)malloc(sizeof(double)*4096);
char *buff=malloc(sizeof(char *)*256);
char *curr;
while(fgets(buff,sizeof(buff),file)){
curr=strtok_r(buff," ",&buff);
int i=0;
while(curr!=NULL){
curr=strtok_r(NULL," ",&buff);
data[i]=strtod(curr,NULL); //this
i++;
}
}
return data;
}
每当我使用 GDB 进行调试并使用 backtrace 命令时,它都会将我带到注释行 //this
。
我无法理解我做错了什么,我开始发疯了!
您需要在相关行之前检查 strtok_r
中的 return 值。
您在调用 strtod()
之前没有检查 curr
的值。
这个:
(...)
while(curr!=NULL){
curr=strtok_r(NULL," ",&buff);
data[i]=strtod(curr,NULL); //this
i++;
}
应该是:
(...)
while(1){
curr=strtok_r(NULL," ",&buff);
if (curr == NULL)
break;
data[i]=strtod(curr,NULL); //this
i++;
}
这个
while(curr!=NULL){
curr=strtok_r(NULL," ",&buff);
data[i]=strtod(curr,NULL); //this
i++;
}
应该是
while(curr!=NULL){
data[i]=strtod(curr,NULL); //this
i++;
curr=strtok_r(NULL," ",&buff); // Looking for next token shall
// be the last statement
}
进一步这条线
char *buff=malloc(sizeof(char *)*256);
错了。应该是
char *buff=malloc(sizeof(char)*256);
^^^^
No *
但一般来说 malloc
最好使用以下形式:
double *data = malloc(4096 * sizeof *data);
^^^^^^^^^^^^
char *buff=malloc(256 * sizeof *buff);
^^^^^^^^^^^^
通过使用 sizeof *varname
,您可以避免简单的类型不匹配。
在你的情况下,你甚至不需要使用 strtok。只需使用管理空白的 strtod :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
double *read_matrix(char *filename){
FILE *file=fopen(filename, "r");
if(!file){
fprintf(stderr, "An error has occurred. Wrong file name?\n");
exit(1);
}
double *data = malloc(10 * sizeof(double));
char *buff = malloc(10 * sizeof(char));
char *end_pointer;
char *newline_pos;
int i = 0;
while(fgets(buff,sizeof(buff),file)){
//removing newline character read by fgets
if ((newline_pos = strchr(buff, '\n')) != NULL) {
*newline_pos = '[=10=]';
}
while (strlen(buff) != 0) {
data[i] = strtod(buff,&end_pointer);
buff = end_pointer;
i++;
}
}
//convenient for printf output
data[i] = '[=10=]';
return data;
}
int main(void) {
char file[] = "matrix.txt";
double *array = read_matrix(file);
int i = 0;
while (array[i] != '[=10=]') {
printf("%f ",array[i]);
i++;
}
printf("\n");
}
您的代码中有多个问题未在其他答案中解决:
double *read_matrix(char *filename){
FILE *file=fopen(filename, "r");
if(!file){
fprintf(stderr, "An error has occurred. Wrong file name?\n");
exit(errno);
}
double *data=(double *)malloc(sizeof(double)*4096);
char *buff=malloc(sizeof(char *)*256);
您需要一个字符缓冲区,而不是指针缓冲区。
char *curr;
while(fgets(buff,sizeof(buff),file)){
sizeof
不会评估缓冲区的大小,而只会评估 char*
的大小,在大多数系统上为 4 或 8。这可能不足以构成完整的一行。
curr=strtok_r(buff," ",&buff);
您正在循环内修改 buff
。当您在循环的下一次迭代中将它用于 fgets
时,您将不会使用从 malloc
.
int i=0;
您将读取的每一行的数组索引设置为 0。最后这只会保留最后一行的值。
while(curr!=NULL){
curr=strtok_r(NULL," ",&buff);
data[i]=strtod(curr,NULL); //this
i++;
}
}
return data;
这只包含最后一行的数字,甚至只包含最后一行前 8 个字节中的数字。 来电者怎么知道你读了多少号码?
}
固定的解决方案可能如下所示:
#define BUFFSIZE 256
double *read_matrix(char *filename, int *numread) {
FILE *file=fopen(filename, "r");
if(!file){
fprintf(stderr, "An error has occurred. Wrong file name?\n");
exit(errno);
}
double *data = malloc(sizeof(double)*4096);
char *buff = malloc(BUFFSIZE);
char *curr = NULL;
char *savetr = NULL;
int i = 0;
while (fgets(buff, BUFFSIZE, file)){
curr = strtok_r(buff, " ", &saveptr);
while(curr != NULL){
data[i] = strtod(curr, NULL);
i++;
curr=strtok_r(NULL, " ", &saveptr);
}
}
if (numread != NULL)
*numread=i;
return data;
}