为什么用c语言声明一个二维数组会出现分段故障?

问题描述 投票:0回答:1

我是一个新的线程,我有一个程序,使用线程从一个2d数组中找出最小数,之后,它找出数组中其他元素与最小数的距离,并将它们存储在另一个数组中。

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

我试着用下面的程序来处理1d数组,它工作得很好。当我把它转换为2d数组时,它开始崩溃并抛出一个分段故障。然而,我找不到2d声明的哪个部分是错误的。

任何帮助都是非常感激的。

这是我的代码。

#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;
}

谢谢你!

c arrays unix pthreads
1个回答
0
投票

你的代码的问题也可能是来自于.NET的问题。

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使用情况的见解。

在声明可变长度数组时,导致分段的原因之一是数值太大,无法在堆栈上分配数组(一些编译器选择了这个选项,这个选择可能有性能原因)。由于在同一堆栈上下文中,几乎没有办法在运行时清理堆栈内存,所以在堆栈上分配内存失败后,没有什么办法可以恢复干净。

你可以通过在堆上分配你的2D数组来缓解这个问题,有一些策略是可用的 这里(感谢@Lundin)此处.

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);

更容易实现(见 这里(感谢@Lundin))

int **arr = malloc(sizeof(int[ptr->s][ptr->s]);
int **B2 = malloc(sizeof(int[ptr->s][ptr->s]);
© www.soinside.com 2019 - 2024. All rights reserved.