为什么通过在 c 中声明二维数组会出现分段错误?

Why do I get a segmentation fault by declaring a 2d array in c?

我是线程的新手,我有一个程序使用线程从二维数组中找出最小数,然后找到数组的其他元素与最小数的距离并存储他们在另一个数组中。

用户应该输入数组的大小和他想使用的线程数。

我尝试了下面的一维数组程序,它工作得很好。当我将它转换为二维数组时,它开始崩溃并抛出分段错误。但是,我找不到二维声明的哪一部分是错误的。

非常感谢任何帮助。

这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <pthread.h>

struct Parameters
{
    // input
    int s,p; //n is size of array, p is number of threads
    int** array; //array with elements
    int start;
    int end;

    // output
    int smallest;
    int pos; //position if minimum
    int** B; //array that holds the distances
};

void* min(void* args)
{
    struct Parameters* p = (struct Parameters*)args;
    int **array = p->array;
    int **B1 = p->B;
    int start = p->start;
    int end = p->end;
    int smallest = array[start][start];
    int pos = p->pos;
    int distance;

    //find the smallest
    for (int i = start; i < end; i++)
    {
        for(int j = start; j < end; j++)
        {
            if (array[i][j] < smallest)
            {
                smallest = array[i][j];
                pos = i;
            }
        }  
    }

    //find the distances
    for(int i = 0; i < ((struct Parameters*)args) -> s; i++)
    {
        for(int j = 0; j < ((struct Parameters*)args) -> s; j++)
        {
            distance = abs(pos - i);
            B1[i][j] = distance;
        }
    }


    params->smallest = smallest;
    params->B = B1;

    return NULL;
}

int main()
{
    int smallest,pos;
    int s,p;

    struct Parameters *ptr = (struct Parameters *)malloc(sizeof(struct Parameters));

    if(ptr == NULL)
    {
        printf("Not enough. Try again \n");
        exit(0);
    }

    printf("Type s\n");
    scanf("%d",&(ptr->s));


    printf("Type p\n");
    scanf("%d", &(ptr->p));

    // declare an array of threads and associated parameter instances
    pthread_t threads[(ptr->p)];
    struct Parameters thread_parameters[(ptr->p)] ;

    int arr[ptr->s][ptr->s];
    int B2[ptr->s][ptr->s];

    // intialize the array    
    for(int i=0; i< ptr->s; i++)
    {
        for(int j=0; j< ptr->s; j++)
        {
        printf("Type a \n");
        scanf("%d",&arr[i][j]);
        }
    }

    // smallest needs to be set to something
    smallest = arr[0][0];

    // start all the threads
    for (int i = 0; i < ptr->p; i++)
    {
        memcpy(arr, thread_parameters[i].array, sizeof(arr));
        thread_parameters[i].s = ptr->s;
        memcpy(Bb, thread_parameters[i].B, sizeof(B2));
        thread_parameters[i].start = i * (ptr->s / ptr->p);
        thread_parameters[i].end = (i+1) * (ptr->s / ptr->p);
        pthread_create(&threads[i], NULL, min, &thread_parameters[i]);
    }

    // wait for all the threads to complete
    for (int i = 0; i < ptr->p; i++)
    {
        pthread_join(threads[i], NULL);
    }

    // Now aggregate the "smallest" and "largest" results from all thread runs    
    for (int i = 0; i < ptr->p; i++)
    {
        if (thread_parameters[i].smallest < smallest)
        {
            smallest = thread_parameters[i].smallest;
        }
    }

    printf("Smallest is %d\n", smallest);

    thread_parameters[ptr->p].B[ptr->s][ptr->s];

    for (int i = 0; i < 1; i++)
    {
        for(int j = 0; j < ptr->s;j++)
        {
            for(int k = 0; k < ptr->s; k++)
            {
                printf("Element %d is %d away from min\n",j,thread_parameters[i].B[j][k]);
            }
        }
   }

    return 0;
}

谢谢!!

您的代码问题也可能来自:

memcpy(arr, thread_parameters[i].array, sizeof(arr));
...
memcpy(Bb, thread_parameters[i].B, sizeof(B2));

因为 thread_parameters[i].arraythread_parameters[i].B 没有分配,如果你只是读取数组,那么只通过地址传递它们可能没问题

thread_parameters[i].array = arr

但对于 thread_parameters[i].B,您需要分配数组并执行深度复制(memcpy 不起作用)


下面的文字没有回答问题,但确实提供了一些关于 VLA 用法的见解

声明可变长度数组导致分段的一个原因是该值太大而无法在堆栈上分配数组(某些编译器选择此选项,此选择可能有性能原因)。
从无法在堆栈上分配内存中完全恢复的选项不多,因为在同一堆栈上下文中运行时几乎没有办法清理堆栈内存。

您可以通过在堆上分配二维数组来缓解这个问题,一些策略可用 and here

int** alloc_2d_int_array(size_t rows, size_t cols) {
     int **result = malloc(rows * sizeof(int *));
     if(result == NULL) {
          // could not allocate more memory
          return NULL;
     }
     size_t row_size = cols * sizeof(int); 
     for(int i=0; i < rows; ++i) {
         result[i] = malloc(row_size);
         if(result[i] == NULL) {
              // could not allocate more memory
              // cleanup
              return NULL;
         }
     }
     return result;
}

以上实现未经测试,但编译通过,仍有整数溢出风险。

然后使用上面的定义函数如下:

int **arr = alloc_2d_int_array(ptr->s, ptr->s);
int **B2 = alloc_2d_int_array(ptr->s, ptr->s);

更容易实施(参见

int **arr = malloc(sizeof(int[ptr->s][ptr->s]);
int **B2 = malloc(sizeof(int[ptr->s][ptr->s]);