带有 const char* 的 printf 中的奇怪 SIGABRT
Strange SIGABRT in printf with const char*
你好 Stack Exchange 社区,
我有一个函数可以将 CSV 文件读入 gsl_matrix,然后 returns 指向矩阵的指针。该函数执行时没有错误,但是当在函数 returns 之后使用常量字符串执行 printf 时,程序以 SIGABRT 退出。我试过:
- 更改打印的字符串
- 将字符串抽象为后跟字符的格式
都没有用,但是我发现在函数调用之前放置一个 printf() 可以防止这个错误(在下面的 main() 中注释掉)。我正在 Ubuntu 16.04 上使用 gcc 5.4.0 进行编译。在此行之前调用 malloc_stats() 表明我正在使用大约 6kB 的堆。下面显示的 LLDB 输出准确说明了哪一行导致 print_matrix().
中的错误
Process 10955 stopped
* thread #1: tid = 10955, 0x000000000040114b main`print_matrix(matrix=0x0000000000604010) + 21 at main.c:88, name = 'main', stop reason = step over
frame #0: 0x000000000040114b main`print_matrix(matrix=0x0000000000604010) + 21 at main.c:88
85 static void print_matrix(gsl_matrix * matrix)
86 {
87 for (int i = 0; i < matrix->size1; i++) {
-> 88 printf("[");
89 for (int j = 0; j < matrix->size2; j++) {
90 printf("%g, ", gsl_matrix_get(matrix, i, j));
91 }
(lldb)
Process 10955 stopped
* thread #1: tid = 10955, 0x00007ffff708d428 libc.so.6`__GI_raise(sig=6) + 56 at raise.c:54, name = 'main', stop reason = signal SIGABRT
frame #0: 0x00007ffff708d428 libc.so.6`__GI_raise(sig=6) + 56 at raise.c:54
下面显示的代码是主函数,它位于main.c:
int main(int argc, char * argv[]) {
/* printf("This is the fix.\n"); */
gsl_matrix * matrix2 = read_tuples_csv("data/12AX7-Data.csv", 3);
print_matrix(matrix2);
}
以下代码是 read_tuples_csv() 函数,它位于 util.c 中。该函数采用要读取的文件路径和要解析的元组的大小。我怀疑问题出在这个函数中,但到目前为止,没有多少校对或调试能够揭示我语义中的错误。
gsl_matrix * read_tuples_csv(const char * filename, size_t n)
{
FILE * file;
if ((file = fopen(filename, "r")) == NULL || n <= 0)
return NULL;
List * list = malloc(sizeof(List));
list_init(list, free);
double * arr;
while (!feof(file)) {
arr = calloc(n, sizeof(double));
char *line = NULL, *scratch;
size_t n = 0;
if (getline(&line, &n, file) == -1) goto error_exit;
line = strtok_r(line, ",", &scratch);
int i = 0;
do {
int ret = sscanf(line, "%lf", &arr[i]);
if (ret <= 0) fprintf(stderr, "Something happened:\nline:\t%s", line);
i++;
} while ((line = strtok_r(NULL, ",", &scratch)) != NULL && i < n);
free(line);
line = NULL;
if (list_insnxt(list, list_tail(list), arr) != 0)
goto error_exit;
}
fclose(file);
file = NULL;
gsl_matrix * matrix = gsl_matrix_alloc(list_size(list), n);
int i = 0;
while (list_size(list) > 0) {
double * vector;
list_remnxt(list, NULL, (void **)&vector);
for (int j = 0; j < n; j++) {
gsl_matrix_set(matrix, i, j, vector[j]);
}
i++;
}
list_dest(list);
free(list);
return matrix;
error_exit: {
if (file != NULL) fclose(file);
list_dest(list);
free(arr);
free(list);
return NULL;
}
}
问题可能是由于:
printf("%g, ", gsl_matrix_get(matrix, i, j));
因为您正在尝试打印一个双精度值,但您的函数返回一个 gsl_matrix 指针。
此外,printf("%s", "[")
或 printf("%c", '[')
比 printf("["
更好。
感谢@SouravGhosh 和@PaulOgilvie 提供答案。问题在于我使用 feof() 作为 while 循环的开关。这是一种糟糕的做法,并且在许多情况下(包括这个)它会导致未定义的行为。为什么这会导致行
printf("[");
失败是我无法接受的。貌似是stdout的buffer overflow,但是我在失败前在stdout上调用fflush()进行了测试,并没有解决问题。如果有人能够确定问题的确切原因,我将不胜感激。还要感谢@SouravGhosh 提醒我忘记检查 calloc() 的 return 值。
你好 Stack Exchange 社区,
我有一个函数可以将 CSV 文件读入 gsl_matrix,然后 returns 指向矩阵的指针。该函数执行时没有错误,但是当在函数 returns 之后使用常量字符串执行 printf 时,程序以 SIGABRT 退出。我试过:
- 更改打印的字符串
- 将字符串抽象为后跟字符的格式
都没有用,但是我发现在函数调用之前放置一个 printf() 可以防止这个错误(在下面的 main() 中注释掉)。我正在 Ubuntu 16.04 上使用 gcc 5.4.0 进行编译。在此行之前调用 malloc_stats() 表明我正在使用大约 6kB 的堆。下面显示的 LLDB 输出准确说明了哪一行导致 print_matrix().
中的错误Process 10955 stopped
* thread #1: tid = 10955, 0x000000000040114b main`print_matrix(matrix=0x0000000000604010) + 21 at main.c:88, name = 'main', stop reason = step over
frame #0: 0x000000000040114b main`print_matrix(matrix=0x0000000000604010) + 21 at main.c:88
85 static void print_matrix(gsl_matrix * matrix)
86 {
87 for (int i = 0; i < matrix->size1; i++) {
-> 88 printf("[");
89 for (int j = 0; j < matrix->size2; j++) {
90 printf("%g, ", gsl_matrix_get(matrix, i, j));
91 }
(lldb)
Process 10955 stopped
* thread #1: tid = 10955, 0x00007ffff708d428 libc.so.6`__GI_raise(sig=6) + 56 at raise.c:54, name = 'main', stop reason = signal SIGABRT
frame #0: 0x00007ffff708d428 libc.so.6`__GI_raise(sig=6) + 56 at raise.c:54
下面显示的代码是主函数,它位于main.c:
int main(int argc, char * argv[]) {
/* printf("This is the fix.\n"); */
gsl_matrix * matrix2 = read_tuples_csv("data/12AX7-Data.csv", 3);
print_matrix(matrix2);
}
以下代码是 read_tuples_csv() 函数,它位于 util.c 中。该函数采用要读取的文件路径和要解析的元组的大小。我怀疑问题出在这个函数中,但到目前为止,没有多少校对或调试能够揭示我语义中的错误。
gsl_matrix * read_tuples_csv(const char * filename, size_t n)
{
FILE * file;
if ((file = fopen(filename, "r")) == NULL || n <= 0)
return NULL;
List * list = malloc(sizeof(List));
list_init(list, free);
double * arr;
while (!feof(file)) {
arr = calloc(n, sizeof(double));
char *line = NULL, *scratch;
size_t n = 0;
if (getline(&line, &n, file) == -1) goto error_exit;
line = strtok_r(line, ",", &scratch);
int i = 0;
do {
int ret = sscanf(line, "%lf", &arr[i]);
if (ret <= 0) fprintf(stderr, "Something happened:\nline:\t%s", line);
i++;
} while ((line = strtok_r(NULL, ",", &scratch)) != NULL && i < n);
free(line);
line = NULL;
if (list_insnxt(list, list_tail(list), arr) != 0)
goto error_exit;
}
fclose(file);
file = NULL;
gsl_matrix * matrix = gsl_matrix_alloc(list_size(list), n);
int i = 0;
while (list_size(list) > 0) {
double * vector;
list_remnxt(list, NULL, (void **)&vector);
for (int j = 0; j < n; j++) {
gsl_matrix_set(matrix, i, j, vector[j]);
}
i++;
}
list_dest(list);
free(list);
return matrix;
error_exit: {
if (file != NULL) fclose(file);
list_dest(list);
free(arr);
free(list);
return NULL;
}
}
问题可能是由于:
printf("%g, ", gsl_matrix_get(matrix, i, j));
因为您正在尝试打印一个双精度值,但您的函数返回一个 gsl_matrix 指针。
此外,printf("%s", "[")
或 printf("%c", '[')
比 printf("["
更好。
感谢@SouravGhosh 和@PaulOgilvie 提供答案。问题在于我使用 feof() 作为 while 循环的开关。这是一种糟糕的做法,并且在许多情况下(包括这个)它会导致未定义的行为。为什么这会导致行
printf("[");
失败是我无法接受的。貌似是stdout的buffer overflow,但是我在失败前在stdout上调用fflush()进行了测试,并没有解决问题。如果有人能够确定问题的确切原因,我将不胜感激。还要感谢@SouravGhosh 提醒我忘记检查 calloc() 的 return 值。