【问题标题】:Save elements in bidimensional array将元素保存在二维数组中
【发布时间】:2020-04-25 22:32:24
【问题描述】:

如何将数字保存在二维数组中?为什么这段代码不起作用?

void input_arr(int *arr, int n, int m);

void print_arr(int *arr, int n, int m);

int main()
{
    int *arr;
    int n, m;

    printf("Insert line of array: ");
    scanf("%d", &n);

    printf("Insert column of array: ");
    scanf("%d", &m);

    arr = calloc(n * m, sizeof(int));

    input_arr(arr, n, m);

    return 0;
}

void input_arr(int *arr, int n, int m)
{
    int i;
    int j;
    for (i = 0; i < n; i++)
    {
        for (j = 0; j < m; j++)
        {
            printf("Insert element in line %d and column %d: ", i, j);
            scanf("%d", (&arr[i][j]));
        }
    }
}

void print_arr(int *arr, int n, int m)
{
    int i, j;
    for (i = 0; i < n; i++)
    {
        for (j = 0; j < m; j++)
        {
            printf("%d ", *arr[i][j]);
        }
    }
}

【问题讨论】:

  • 请显示调用该函数的代码。 stackoverflow.com/help/minimal-reproducible-example
  • 那是因为int *arr 不是代表二维数组的类型(甚至不是表现得像二维数组的东西)。您实际上是在将二维数组传递给函数吗?请提供minimal verifiable example。另外,请定义“不起作用” - 编译错误?碰撞?不正确的价值观?什么?
  • @Boninissimo 对我来说该功能有效!:) 看来您使用该功能不正确。
  • @VladfromMoscow 该功能不能工作,至少不能以定义的行为工作。他在单级指针上使用双索引 [i][j]。
  • @DarkAtom 还有什么?他可以对这样的数组使用运算符。没问题!

标签: c arrays multidimensional-array


【解决方案1】:

像这样替换你的函数声明:

void input_arr(int *arr[], int n, int m)
void print_arr(int *arr[], int n, int m)

无论您在哪里有 scanfprintf 调用数组元素,都可以使用:

scanf("%d", arr + i * m + j);
printf("%d", *(arr + i * m + j));

为了获得良好的实践,请在完成后释放内存。在main() 末尾添加:

free(arr);

另外,如果您有 C99 或更高版本的编译器,您可以使用 可变长度数组 来完成这项工作,并允许您使用 arr[i][j] 而不是丑陋的 arr + i * m + j 来索引数组.

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

//note that the arr parameter must be declared AFTER the m parameter since it uses its information
void input_arr(int n, int m, int arr[][m]);

void print_arr(int n, int m, int arr[][m]);

int main(void)
{
    int n, m;

    printf("Insert line of array: ");
    scanf("%d", &n);

    printf("Insert column of array: ");
    scanf("%d", &m);

    int arr[n][m];

    input_arr(n, m, arr);

    print_arr(n, m, arr); //I am assuming you also want to print the array

    //return 0; //not needed in C99
}

void input_arr(int n, int m, int arr[][m])
{
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            printf("Insert element in line %d and column %d: ", i, j);
            scanf("%d", &arr[i][j]);
        }
    }
}

void print_arr(int n, int m, int arr[][m])
{
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            printf("%d ", arr[i][j]);
        }
        //you probably want a new line here to display it as a matrix
        printf("\n");
    }
}

【讨论】:

    【解决方案2】:

    您正在传递一个指向分配空间的指针,它被存储为一个线性数组,做您想做的事情,一个二维数组,或者可以以相同方式使用的东西,您需要:

    1. 行的指针数组,并为每一个模拟列分配内存。
    2. 双指针并分配内存以模拟行和列的方式存储值。
    3. 您还可以使用线性数组,使输入和输出看起来像是一个二维数组。
    4. 或者您可以只使用普通的普通二维数组。

    由于您正在使用内存分配here is a possible implementation 使用双指针:

    #include <stdio.h>
    #include <stdlib.h>
    
    void input_arr(int **arr, int n, int m); //double pointer to int parameter
    void print_arr(int **arr, int n, int m); //same
    
    int main() {
    
        int n, m;
        int **arr; //double pointer for 2D array like memory allocation
    
        printf("Insert line of array: ");
    
        if(scanf("%d", &n) != 1 || n < 1) {  //always check input
            puts("positive integer value expected!"); 
            return 1;
        }
    
        printf("Insert column of array: ");
    
        if(scanf("%d", &m) != 1 || m < 1) {  //always check input
            puts("positive integer value expected!");
            return 1;
        }
    
        if(!(arr = malloc(n * sizeof(*arr)))){ //allocate memory lines, check for errors
            perror("Memory allocation failed!");
            return 1;
        }
    
        for(int i = 0; i < n; i++)
            if(!(arr[i] = malloc(m * sizeof(**arr)))) { //allocate memory for columns, check for errors
                perror("Memory allocation failed");
                return 1;
            }
    
        input_arr(arr, n, m);
        print_arr(arr, n, m);
    
        return 0;
    }
    
    void input_arr(int **arr, int n, int m) {
    
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                printf("Insert element in line %d and column %d: ", i, j);
                scanf("%d", &arr[i][j]);
            }
        }
    }
    
    void print_arr(int **arr, int n, int m) {
    
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                printf("%d ", arr[i][j]); //no dereferencing
            }
            putchar('\n');
        }
    }
    

    【讨论】:

    • 这可能是 OP 想要/需要的,但 char **arr 不是二维数组。
    • 当然@Boninissimo,所以在arr = malloc(n * sizeof(*arr) 中,我正在为一组指针分配内存(如果你愿意,可以使用行),这些指针中的每一个都将指向每一行的开头,然后在for(int i = 0; i &lt; n; i++) if(!(arr[i] = malloc(m * sizeof(**arr)... 中,我为这些行中的每一行分配内存。 sizeof(*arr)sizeof(int*) 相同,表示指向int 的指针的大小,我为这些指针中的每一个分配内存。 sizeof(**arr)sizeof(int) 一样,我正在为该行中的所有 ints 分配内存。
    • 我为什么要那样做,因为你现在想改变你的代码并且你想要一个doubles的数组,你需要改变所有的sizeofs,如果你忘记了其中一个您的程序将失败而没有错误,因为 malloc 仍然可以正常工作,但是分配的空间对于您的需要来说太小了,使用此构造您只需将 arr 的声明从 int 更改为 @987654336 @ 一切都会好起来的。
    • 这将允许您像以前一样使用数组表示法arr[i][j],其优点是您现在使用分配的内存避免了堆栈大小问题。我知道这可能会带来很多问题,所以如果您仍有疑问,请告诉我。
    • 我明白了!谢谢@anastaciu
    【解决方案3】:

    代码分配并初始化一块连续的内存,并将指向int 的指针传递给函数。问题是在这些函数内部,该指针被取消引用太多次。

    void input_arr(int *arr, int n, int m)
    {
        // ...
        scanf("%d", (&arr[i][j]));
        //                  ^^^ 
    }
    
    void print_arr(int *arr, int n, int m)
    {
        // ...
        printf("%d ", *arr[i][j]);
        //            ^      ^^^
    }
    

    如果您可以使用可变长度数组,则与其他答案中已经发布的不同的选项是在这些函数中声明指向 VLA 的指针:

    void input_arr(int *arr, int n, int m)
    {
        // ...
        scanf("%d", arr++);
        //          ^^^ Here you can just access to every element in order 
    }
    
    void print_arr(int *arr, int n, int m)
    {
        // Declare a pointer to array of m elements
        int (*mat)[m] = (void *)arr;
    
        // ...
        printf("%d ", mat[i][j]);
        //            ^^^^^^^^^  Use it as if it's a 2D VLA
    }
    

    另外,记得释放main中分配的内存。

    【讨论】:

      【解决方案4】:

      如何将数字保存在二维数组中?

      例子:

      int twoD[2][3];
      twoD[1][1] = 42;
      

      为什么这段代码不起作用?

      OP 的代码使用的不是二维数组,而是指向int 的指针,然后错误地使用了该指针。

      int *arr;
      // Allocate memory for a 1-D array of  n*m `int` 
      arr = calloc(n * m, sizeof(int));
      

      函数代码尝试取消引用int

      void input_arr(int *arr, int n, int m) {
        ...
        scanf("%d", (&arr[i][j])); // bad
      

      这里的arr[i]intarr[i][j] 毫无意义。


      要分配内存,你需要一个指针,但是什么类型呢?

      你想要一个指向二维数组的指针吗,如下,
      指向int [m]DarkAtom数组的指针
      还是指向int@anastaciu的指针数组的指针?

      int (*TwoD)[m][n] = malloc(sizeof *Two);
      (*TwoD)[1][1] = 42;
      ....
      

      或者以类似 2D 的方式使用当前代码并使用计算索引访问 1D 数组分配。

      // scanf("%d", (&arr[i][j]));
      scanf("%d", &arr[i*m + j]);
      
      // printf("%d ", *arr[i][j]);
      printf("%d ", arr[i*m + j]);
      

      【讨论】:

        【解决方案5】:

        您需要将数组作为双指针(int **array 或更简单的 int *array[])传递。

        说明 通过将数组作为 int* 数组传递,当您说 &array[i] 时,您是在推断数组的复制值而不是原始值。 具体来说,在一个函数中,当你只想读取(或/和打印)数组数据时,你可以简单地使用单指针,但如果你想改变它,你必须使用双指针。

        【讨论】:

        • 这会起作用,但调用者代码可能也需要修改(取决于数组的声明方式)。
        • 是的,这是正确的,虽然没有办法解决
        • 你的解释是错误的。您需要双指针的原因是因为它是一个双向数组。该函数总是可以修改调用者数组的内容,除非它是const 参数,因为数组是通过它的地址传递的。
        猜你喜欢
        • 2017-04-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-03
        • 2014-09-14
        相关资源
        最近更新 更多