使用fgets与字符串数组时出现分段错误

huangapple go评论70阅读模式
英文:

Segmentation fault when using fgets with array of strings

问题

需要将文件的一行添加到字符串数组中,但当它执行fgets函数时,出现了分段错误。

```c
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE *file = fopen("test.txt", "r"); 
    char **array = malloc((sizeof(char) * 100) * 3);
    fgets(*(array), 100, file);
    printf("%s\n", *array);
    free(array);
    return 0;
}

在这段代码中,我试图将文件的第一行("My name is bob" 是第一行)添加到数组的第零个元素中。但每当它执行fgets语句时,都会出现分段错误。


<details>
<summary>英文:</summary>

I need to add a line of a file to a array of strings but am getting a segmentation fault when it hits the fgets function.

```c
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

int main(void)
{
    FILE *file = fopen(&quot;test.txt&quot;, &quot;r&quot;); 
    char **array = malloc((sizeof(char) * 100) * 3);
    fgets(*(array), 100, file);
    printf(&quot;%s\n&quot;, *array);
    free(array);
    return 0;
}

In this code I am trying to add the first line of the file ("My name is bob" is the first line) and set it to the zeroth element of the array. I am getting a segmentation whenever it hits the fgets statement.

答案1

得分: 0

  1. 检查fopen()的返回值。

  2. 检查malloc()的返回值。

  3. char **array = malloc((sizeof(char) * 100) * 3); 分配了300字节,你说它们是char *,然后尝试在其中写入char。解引用未初始化的数据是未定义行为。

  4. 使用fclose(file)关闭你的文件句柄是一个好习惯。

  5. 使用符号常量而不是魔术值。

如果你想动态执行,你可以使用一个指向字符串数组的指针:

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

#define LINE_LEN 100
#define LINES 3

int main(void) {
    FILE *file = fopen("test.txt", "r");
    if(!file) {
        perror("test.txt");
        return 1;
    }
    char (*array)[LINES][LINE_LEN] = malloc(sizeof *array);
    if(!array) {
        perror("malloc");
        fclose(file);
        return 1;
    }
    fgets((*array)[0], sizeof *(*array)[0], file);
    printf("%s\n", (*array)[0]);
    fclose(file);
    return 0;
}

或者一个字符串数组:

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

#define LINE_LEN 100
#define LINES 3

int main(void) {
    FILE *file = fopen("test.txt", "r");
    if(!file) {
        perror("test.txt");
        return 1;
    }
    char (*array)[LINE_LEN] = malloc(sizeof *array * LINES);
    if(!array) {
        perror("malloc");
        fclose(file);
        return 1;
    }
    fgets(array[0], sizeof array[0], file);
    printf("%s\n", array[0]);
    fclose(file);
    return 0;
}

使用一个栈分配的变量会更容易:

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

#define ARRAY_LEN 100

int main(void) {
    FILE *file = fopen("test.txt", "r");
    if(!file) {
        perror("test.txt");
        return 1;
    }
    char array[ARRAY_LEN];
    fgets(array, sizeof array, file);
    printf("%s\n", array);
    fclose(file);
    return 0;
}
英文:
  1. Check the return value from fopen().

  2. Check the return value from malloc().

  3. char **array = malloc((sizeof(char) * 100) * 3); allocates 300 bytes which you say are char * then try to write char in it. Dereferencing uninitialized data is undefined behavior.

  4. Close your file handle with fclose(file) is a good practice.

  5. Use symbolic constants instead of magic values.

If you want to do it dynamically you could use a pointer to array of strings:

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

#define LINE_LEN 100
#define LINES 3

int main(void) {
	FILE *file = fopen(&quot;test.txt&quot;, &quot;r&quot;);
	if(!file) {
		perror(&quot;test.txt&quot;);
		return 1;
	}
	char (*array)[LINES][LINE_LEN] = malloc(sizeof *array);
    if(!array) {
        perror(&quot;malloc&quot;);
        fclose(file);
        return 1;
    }
	fgets(*array[0], sizeof *array[0], file);
	printf(&quot;%s\n&quot;, *array[0]);
	fclose(file);
	return 0;
}

or an array of string:

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

#define LINE_LEN 100
#define LINES 3

int main(void) {
	FILE *file = fopen(&quot;test.txt&quot;, &quot;r&quot;);
	if(!file) {
		perror(&quot;test.txt&quot;);
		return 1;
	}
	char (*array)[LINE_LEN] = malloc(sizeof *array * LINES);
    if(!array) {
        perror(&quot;malloc&quot;);
        fclose(file);
        return 1;
    }
    fgets(array[0], sizeof array[0], file);
	printf(&quot;%s\n&quot;, array[0]);
	fclose(file);
	return 0;
}

It would be easier to use a stack allocated variable:

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

#define ARRAY_LEN 100

int main(void) {
	FILE *file = fopen(&quot;test.txt&quot;, &quot;r&quot;);
	if(!file) {
		perror(&quot;test.txt&quot;);
		return 1;
	}
	char array[ARRAY_LEN];
	fgets(array, sizeof array, file);
	printf(&quot;%s\n&quot;, array);
	fclose(file);
	return 0;
}

答案2

得分: 0

fgets 语句执行时,每当发生分段错误时。

在以下代码之后:

char **array = malloc((sizeof(char) * 100) * 3);

array 指向未初始化的分配内存。

使用以下代码:

fgets(*(array), 100, file);

*array 是不好的,因为array 指向的内存是未初始化的。代码传递了一个指针,具有不确定的值,导致未定义的行为(UB)。


为了创建一个包含3个字符串的数组(使用大小为100的字符数组)并进行一次分配:

#define ARRAY_N 3
#define STRING_SZ 100
char (*array_alt)[STRING_SZ] = malloc(sizeof *array_alt * ARRAY_N);
if (array_alt) {
  for (size_t i = 0; i < ARRAY_N; i++) {
    if (fgets(array_alt[i], sizeof array_alt[i], file) == NULL) {
      array_alt[i][0] = '
#define ARRAY_N 3
#define STRING_SZ 100
char (*array_alt)[STRING_SZ] = malloc(sizeof *array_alt * ARRAY_N);
if (array_alt) {
  for (size_t i = 0; i < ARRAY_N; i++) {
    if (fgets(array_alt[i], sizeof array_alt[i], file) == NULL) {
      array_alt[i][0] = '\0';
    }
    printf("<%s>\n", array_alt[i]);
  }
  free(array_alt);
}
'
;
} printf("<%s>\n", array_alt[i]); } free(array_alt); }

使用 char (*array_alt)[STRING_SZ]array 是指向大小为100的字符数组的指针。

这里 array_alt[i] 引用了一个大小为100的字符数组。将其传递给 fgets() 时,它会转换为该类型(char *)和其第一个元素的地址(&array_alt[i][0]),这正是 fgets() 预期的。

英文:

> I am getting a segmentation whenever it hits the fgets statement.

After

char **array = malloc((sizeof(char) * 100) * 3);

array points to to the uninitialized allocated memory.

With:

fgets(*(array), 100, file);

*array is bad as the memory array points to is initialized. Code is passing a pointer, with an indeterminant value resulting in undefined behavior (UB).


To form an array (size 3) of strings (using a size 100 char array) with 1 allocation:

#define ARRAY_N 3 
#define STRING_SZ 100 
char (*array_alt)[STRING_SZ] = malloc(sizeof *array_alt * ARRAY_N);
if (array_alt) {
  for (size_t i = 0; i &lt; ARRAY_N; i++) {
    if (fgets(array_alt[i], sizeof array_alt[i], file) == NULL) {
      array_alt[i][0] = &#39;
#define ARRAY_N 3 
#define STRING_SZ 100 
char (*array_alt)[STRING_SZ] = malloc(sizeof *array_alt * ARRAY_N);
if (array_alt) {
for (size_t i = 0; i &lt; ARRAY_N; i++) {
if (fgets(array_alt[i], sizeof array_alt[i], file) == NULL) {
array_alt[i][0] = &#39;\0&#39;;
}
printf(&quot;&lt;%s&gt;\n&quot;, array_alt[i]);
}
free(array_alt);
}
&#39;; } printf(&quot;&lt;%s&gt;\n&quot;, array_alt[i]); } free(array_alt); }

With char (*array_alt)[STRING_SZ], array is a pointer to array 100 of char.

Here array_alt[i] refences an array of char, size 100. Giving that to fgets(), it is converted to the type (a char *) and address of its first element (&amp;array_alt[i][0]), just what fgets() expects.

huangapple
  • 本文由 发表于 2023年7月14日 09:35:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76684199.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定