C中的分段错误问题(核心转储)

Posted

技术标签:

【中文标题】C中的分段错误问题(核心转储)【英文标题】:Segmentation fault problem in C (core dumped) 【发布时间】:2021-06-03 19:51:07 【问题描述】:
#include <stdio.h>
#include <stdlib.h>

struct arrayADT 

  int *A;
  int size;
  int length;
  int *B;
  int arr3;
;
struct arrayADT * MergeArray(struct arrayADT *arr1, struct arrayADT *arr2)     //we create thus in heap cuz we need to be able to use these in main function
  
  struct arrayADT *arr3 = (struct arrayADT *)malloc((sizeof(struct arrayADT)));

  int i, j, k;
  i = j = k = 0;

  while(i < arr1->length && j < arr1->length ) 
    if(arr1->A[i] < arr2->A[j]) 
      arr3->A[k] = arr1->A[i];
      k++;
      i++;
    

    else 
      arr3->A[k] = arr2->A[j];
      k++;
      j++;
    
  

  for(; i<arr1->length ; i++) 
    arr3->A[k] = arr1->A[i];
    k++;
  

  for(; j < arr2->length ; j++) 
    arr3->A[k] = arr2->A[j];
    k++;
  

  arr3->length = arr1->length + arr2->length;
  arr3->length = 10;
  
  

void main() 

  struct arrayADT arr;
  printf("Enter the size of an array");
  scanf("%d", &arr.size);

  arr.A = (struct arrayADT *)malloc(arr.size * sizeof(int));

  arr.length = 0;
  int n;
  printf("enter the number of elements in an array");
  scanf("%d", &n);
  printf("enter the elements");
  for(int i = 0; i < n; i++) 
    scanf("%d", &arr.A[i]);
  
  arr.length = n;
  display(arr);
  printf("Enter second array");
  
  int j;
  struct arrayADT *B = (struct arrayADT *)malloc((sizeof(struct arrayADT)));
  for(j = 0; j < arr.length; j++) 
    scanf("%d", &B[j]);
  
  struct arrayADT *arr3 = (struct arrayADT *)malloc(sizeof(struct arrayADT));
  arr3 = MergeArray(&arr, &B);
  display(*arr3);

我希望使用堆内存合并这些数组,但我遇到了分段错误。我是使用指针进行 C 编程的新手,我在这里被打动了,如果我在你的帮助下通过了这个障碍,那将非常有帮助。 而且我没有找到我的错误所在,如果有人也指定这一点会很有帮助,这样我以后就可以避免这些错误。 PS:我正在使用 minGW 编译器。

【问题讨论】:

您为arr3 分配内存,但没有为其中的AB 指针分配内存。您也不会从您的函数返回一个值,该值表示它将返回 struct arrayADT * 我返回了值,但问题仍然没有解决。但是我不明白你所说的我没有分配内存 arr3 但没有分配其中的 A 和 B 指针。 我不明白你的结构的结构。 (显然你也不是。)当然,该结构代表一个具有长度和最大容量的数组,但Barr3 字段是干什么用的?顺便说一句,您的数据成员的名称与三个数组结构的名称相同,并且您在代码中混淆了它们的使用。 如果你打开警告,你会发现你搞错了几件事:arr.A 不是(struct arrayADT *),它是(int *)。另一方面,您不能scanf("%d", &amp;B[j]);,因为B[j] (struct arrayADT *),而不是(int *)。这也是你的 seggie 出现的地方,因为B[1] 将是结构数组中的第二个结构,但你只有一个结构,B @MOehm 感谢您的回复。我是指针的初学者,所以我尝试了一种偏离我的导师的方法,我得到了这个错误。你能纠正我犯的错误并帮助我吗 【参考方案1】:

一般来说,您的代码是无组织的。有几种未定义行为的情况,例如您没有正确扫描第二个数组。您的分段错误最有可能的候选者在这里:

struct arrayADT *arr3 = (struct arrayADT *)malloc((sizeof(struct arrayADT)));

这会给你一个未初始化的内存块。 arr3 的长度和大小可以是任意值,其数据字段A 不指向有效内存。访问它可能会崩溃。

您的代码中有三个数组。您逐步构建每一个,并以不同的方式对待每一个。这很容易导致错误。让我们更系统地讨论这个问题。

让我们为固定大小的数组创建一个结构类型:最大大小必须在创建时给出,并且不能更改。数组的实际长度可以是从 0 到其最大大小的任何值。

typedef struct Array Array;

struct Array 
  int *value;         // data array
  int length;         // actual length, 0 <= length <= size
  int size;           // maximum capacity
;

我们在堆上创建这样的数组,因为初始化成员容易出错,我们编写了一个构造函数:

Array *array_create(int size)

    Array *array = calloc(1, sizeof(*array));
    
    array->size = size;
    array->value = calloc(size, sizeof(*array->value));
    
    return array;

此函数最多为size 整数创建一个空数组。如果我们分配内存,我们必须在稍后释放它,所以让我们编写一个相应的析构函数,它清理资源:

void array_destroy(Array *array)

    if (array) 
        free(array->value);
        free(array);
    

数组销毁后就不能再使用了,就像内存调用free()后一样。

数组一开始是空的,所以让我们编写一个函数,如果有空间,则在其末尾添加元素:

void array_push(Array *array, int x)

    if (array->length < array->size) 
        array->value[array->length++] = x;
    

还有一个打印它的函数:

void array_print(const Array *array)

    printf("[");
    
    for (int i = 0; i < array->length; i++) 
        if (i) printf(", ");
        printf("%d", array->value[i]);
    
    
    printf("]\n");

现在你可以像这样创建数组了:

Array *a = array_create(10);

for (int i = 0; i < a->size; i++) 
    array_push(a, i);


array_print(a);
array_destroy(a);

您的合并功能也会更简单。这是一个完整的例子。 (但使用的是生成的数组,而不是用户输入的数组。)

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

typedef struct Array Array;

struct Array 
  int *value;
  int length;
  int size;
;

Array *array_create(int size)

    Array *array = calloc(1, sizeof(*array));
    
    array->size = size;
    array->value = calloc(size, sizeof(*array->value));
    
    return array;


void array_destroy(Array *array)

    if (array) 
        free(array->value);
        free(array);
    


void array_push(Array *array, int x)

    if (array->length < array->size) 
        array->value[array->length++] = x;
    


void array_print(const Array *array)

    printf("[");
    
    for (int i = 0; i < array->length; i++) 
        if (i) printf(", ");
        printf("%d", array->value[i]);
    
    
    printf("]\n");


Array *merge(Array *a, Array *b)

    Array *res = array_create(a->length + b->length);

    int i = 0;
    int j = 0;

    while(i < a->length && j < b->length) 
        if(a->value[i] < b->value[j]) 
            array_push(res, a->value[i++]);
         else 
            array_push(res, b->value[j++]);
        
    

    while(i < a->length) 
        array_push(res, a->value[i++]);
    

    while(j < b->length) 
        array_push(res, b->value[j++]);
    
    
    return res;


int main(void)

    Array *a = array_create(10);
    Array *b = array_create(6);
    Array *c;
    
    for (int i = 0; i < a->size; i++) 
        array_push(a, 1 + 3 * i);
    
    
    for (int i = 0; i < b->size; i++) 
        array_push(b, 4 + 2 * i);
    
    
    array_print(a);
    array_print(b);
    
    c = merge(a, b);

    array_print(c);
    
    array_destroy(a);
    array_destroy(b);
    array_destroy(c);

    return 0;

如果您到目前为止已经阅读过,下面是内幕:

整理您的代码。这适用于代码布局,就像编写小的、普遍适用的函数一样,而不是“手工”做所有事情。 (上面的数组类型有点悬念:它使用函数,但仍然通过访问结构字段来获取数据。您甚至可以更改 szie 和长度,但实际上不应该发生这种情况。)

使用-Wall 启用编译器警告。您将获得有关潜在(通常是实际)错误的有用信息。

祝你好运!

【讨论】:

非常感谢先生。我从这位先生身上学到了很多。我欠你一大笔钱

以上是关于C中的分段错误问题(核心转储)的主要内容,如果未能解决你的问题,请参考以下文章

C中的Minishell“分段错误,核心转储”错误

在opencv c ++中查找图像卷积时出现分段错误(核心转储)错误

识别导致分段错误(核心转储)的错误

recvfrom 中的分段错误(已创建核心转储)

最简单的字符串数组c程序上的分段错误(核心转储)

为啥我在 C 中收到警告“分段错误,核心转储”