为什么C在这里需要指针解引用?

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

这是一个带有

warning: incompatible pointer to integer conversion initializing. 'int' with an expression of type 'int *'; dereference with *
,

的小 C 程序
#include <stdio.h>
#include <stdlib.h>

#define N 3
typedef struct node {
  int arr[N];
} node;

node *new_node(int arr[N]) {
  node *x = (node *)malloc(sizeof(node));
  *x = (node){arr};
  return x;
}

int main() {
  int arr[N] = {0, 1, 2};
  node *x = new_node(arr);
  for (int i = 0; i < 3; i++)
    printf("%d\n", x->arr[i]);
}

取消引用

*x = (node){*arr};
可以解决警告,但程序不会产生预期的输出。

我的 C 有点生疏,但据我了解,每当您将数组传递给函数时,您实际上都会传递一个指向其第一个元素的指针。因此,上面的内容应该与这个程序相同(顺便说一句,它按预期工作)。

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

#define N 3
typedef struct node {
  int *arr;
} node;

node *new_node(int *arr) {
  node *x = (node *)malloc(sizeof(node));
  *x = (node){arr};
  return x;
}

int main() {
  int arr[N] = {0, 1, 2};
  node *x = new_node(arr);
  for (int i = 0; i < 3; i++)
    printf("%d\n", x->arr[i]);
}

我这里没有什么 C 细节?

arrays c function pointers
1个回答
0
投票

每当您将数组传递给函数时,您实际上都会传递一个指向其第一个元素的指针

这是正确的;就所有意图和目的而言,这两个函数

foo(int a[])
foo(int* a)
是相同的。

上面应该和这个程序一样

然而,这是正确的。

new_node
函数的不同参数类型 (
int arr[N]
vs
int *arr
) 不是两个代码片段之间唯一的区别
node
结构也存在显着差异。

在第二个片段中,

struct
的第一个成员是
int*
,并且将结构强制转换为其第一个成员的类型(反之亦然)是有效的C;然而,在第一个片段中,结构中没有指针(数组不是指针,尽管在许多表达式中,它“衰减”为指向其第一个元素的指针)。

在第一个片段中,结构的第一个成员(也就是说,该结构起始地址处的数据类型)实际上是“数组的第一个元素”。因此,当您这样做时,*x = (node){ arr };

arr
标识符会衰减为指针,但赋值的转换和 LHS 引用
int
的位置。
要设置结构体数组成员的值,您需要将参数指向的内存复制到结构体中:

node* new_node(int arr[N]) { node* x = (node*)malloc(sizeof(node)); memcpy(x, arr, sizeof(int) * N); return x; }

或者,您可以在两个代码片段之间使用“混合”:将 
int arr[N]

参数设置为

new_node
(如您的第一种情况),但使用
int *arr
struct node
成员(如您的第二个情况)案件)。然后它将按预期工作:
#include <stdio.h>
#include <stdlib.h>

#define N 3
typedef struct node {
    int *arr;
} node;

node* new_node(int arr[N])
{
    node* x = malloc(sizeof(node));
    *x = (node){ arr }; // Member pointer is assigned value of passed pointer
    return x;
}

int main()
{
    int arr[N] = { 0, 1, 2 };
    node* x = new_node(arr); // Address is passed
    for (int i = 0; i < 3; i++) {
        printf("%d\n", x->arr[i]); // Works!
    }
    free(x);
    return 0;
}

© www.soinside.com 2019 - 2024. All rights reserved.