理解指向指针数组的指针作为函数中的参数

时间:2017-04-11 19:26:27

标签: c arrays pointers

在尝试自己学习C的同时,我遇到了这个我想要开发的简单程序。它只是试图利用指向指针数组的指针来制作类似于矩阵的东西。我在Windows上编译,当我运行它时,它只是崩溃,同时,在Linux上尝试这个代码,它说segmentation fault,这是因为函数参数是数组吗?我在这里做错了什么?

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

void initializeArray(float** array, int size);
void printArray(float** array, int size);

int main()
{
    float** array_1 = NULL;
    int array_size = 3;

    initializeArray(array_1, array_size);

    // Free memory from array
    for (int i = 0; i < array_size; i++)
    {
        free(array_1[i]);
    }

    free(array_1);

    return 0;
}

void initializeArray(float** array, int size)
{
    array = malloc(size * sizeof(float*));

    if (array)
    {
        for (int i = 0; i < size; i++)
        {
            array[i] = malloc(size * sizeof(float));
            if (!array[i])
            {
                exit(0);
            }
        }
    }

    for (int i = 0; i < size; i++)
    {
        for (int j = 0; j < size; j++)
        {
            array[i][j] = 0;
        }
    }
}


void printArray(float** array, int size)
{
    for (int i = 0; i < size; i++)
    {
        for (int j = 0; j < size; j++)
        {
            printf("%f\t", array[i][j]);
        }

        printf("\n");
    }
}

2 个答案:

答案 0 :(得分:1)

做的时候:

void initializeArray(float** array, int size)
{
    array = malloc(size * sizeof(float*));

你没有在函数外部更改array,因此array_1在调用之后(像之前一样)指向NULL(并创建内存泄漏)。您需要将其返回(或将其作为三***指针传递并将其用作*array,但这不太方便。

float **initializeArray(int size)
{
    float** array = malloc(size * sizeof(float*));
   ...
    return array;
}

来自main:

array_1 = initializeArray(array_size);

答案 1 :(得分:0)

如果希望函数修改参数的值,则必须传递指向该参数的指针:

void foo( T *ptr )
{
  *ptr = new_value(); // write a new value to the thing ptr points to
}

void bar( void )
{
  T var;
  foo( &var ); // write a new value to var 
}

任何类型T 都是如此,包括指针类型。将T替换为P *,我们就会

void foo( P **ptr )
{
  *ptr = new_value(); // write a new value to the thing ptr points to
}

void bar( void )
{
  P *var;
  foo( &var ); // write a new *pointer* value to var
}

基本上,无论var的类型如何,ptr都需要一个更多级别的间接。

将其应用于您的代码:

void initializeArray(float*** array, int size)
{
    *array = malloc(size * sizeof(float*));

    if (*array)
    {
        for (int i = 0; i < size; i++)
        {
            (*array)[i] = malloc(size * sizeof(float)); // parens matter; you want
            if (!(*array)[i])                           // to index into what array *points
            {                                           // to*, not array itself
                exit(0);
            }
        }
    }

    for (int i = 0; i < size; i++)
    {
        for (int j = 0; j < size; j++)
        {
            (*array)[i][j] = 0;
        }
    }
}

将从main调用为:

initializeArray(&array_1, array_size);

一些建议:

首先,在调用malloc时,将sizeof运算符的操作数设为取消引用的目标,而不是类型名称:

ptr = malloc( N * sizeof *ptr );

在你的情况下,它将是

*array = malloc( size * sizeof **array ); // sizeof operand has one more level of 
                                          // indirection than target

(*array)[i] = malloc( size * sizeof *(*array)[i] );

如果您更改array的类型,这将保护您;您不必追逐sizeof (float)sizeof (float *)的每个实例并更改这些实例。

其次,你所分配的不是2D数组 - 它是一个指针数组,每个指针指向一个单独的float数组。哪个非常好,取决于你正在做什么,只要知道行在内存中不相邻 - array[1][2]之后的对象将是{{1 }}。

如果您想分配连续的多维数组,您可以使用

之类的内容
array[2][0]

为连续的3x3阵列留出空间。使用VLA语法,您可以编写类似

的函数
float (*array)[3] = malloc( 3 * sizeof *array );