鱼C论坛

 找回密码
 立即注册
查看: 134|回复: 8

[已解决]指针与数组

[复制链接]
发表于 2024-7-31 13:08:03 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
代码1:
#include <stdio.h>
#include <stdlib.h>

#define Node_num 1
#define STR '&'

struct Node {
  char str;
  int x, y;
};

void init(struct Node **node, int num);

int main(void) {
  struct Node node[Node_num];
  // node : struct Node node*

  init(&node, Node_num);
  printf("Ok\n");

  return 0;
}

void init(struct Node **node, int num) {
  for (int i = 0; i < num; i++) {
    (*(node) + i)->str = STR;
  }
};
报错:
$ gcc game_1.c &&./a.out
game_1.c: 在函数‘main’中:
game_1.c:18:8: 错误:传递‘init’的第 1 个参数时在不兼容的指针类型间转换 [-Wincompatible-pointer-types]
   18 |   init(&node, Node_num);
      |        ^~~~~
      |        |
      |        struct Node (*)[1]
game_1.c:12:25: 附注:需要类型‘struct Node **’,但实参的类型为‘struct Node (*)[1]’
   12 | void init(struct Node **node, int num);
      |           ~~~~~~~~~~~~~~^~~~

代码2:
#include <stdio.h>
#include <stdlib.h>

#define Node_num 1
#define STR '&'

struct Node {
  char str;
  int x, y;
};

void init(struct Node *node, int num);

int main(void) {
  struct Node node[Node_num];
  // node : struct Node node*

  init(node, Node_num);
  printf("Ok\n");

  return 0;
}

void init(struct Node *node, int num) {
  for (int i = 0; i < num; i++) {
    (*(node + i)).str = STR;
  }
};
通过:
$ gcc game_1.c &&./a.out
Ok
为什么?
最佳答案
2024-8-8 12:16:14
风眠 发表于 2024-8-4 11:10
那如果我要这么做,那么我应该怎么声明呢?
 struct Node node[Node_num];

 init(&node, Node_num);

我们首先分析,对数组取地址,得到的是什么?

C语言标准规定,当数组名作为数组定义的标识符(也就是定义或声明数组时)、sizeof 或 & 的操作数时,它才表示整个数组本身,在其他的表达式中,数组名会被转换为指向第 0 个元素的指针(地址)。

也就是,&node得到的是数组的地址。

因此在编译器编译时,会出现类似错误:
error C2664: 'init' : cannot convert parameter 1 from 'struct Node (*)[1]' to 'struct Node ** '

你想得到的是数组内的一个具体元素的指针,然后以指针的形式,取进行赋值。

所以,先考虑如何得到这个数组元素的指针:
struct Node node[Node_num];
node即为第一个元素的指针。

所以,第一种方法:
#include <stdio.h>
#include <stdlib.h>

#define Node_num 1
#define STR '&'

struct Node {
  char str;
  int x, y;
};

void init(struct Node *node, int num);

int main(void) {
  struct Node node[Node_num];
  // node : struct Node node*

  init(node, Node_num);
  printf("Ok\n");

  return 0;
}

void init(struct Node *node, int num) {
  for (int i = 0; i < num; i++) {
    ((node) + i)->str = STR;
  }
};


如果非要用原帖子内的这模式来完成,那么可以改成
#include <stdio.h>
#include <stdlib.h>

#define Node_num 1
#define STR '&'

struct Node {
  char str;
  int x, y;
};

void init(struct Node **node, int num);

int main(void) {
  struct Node node[Node_num];
  // node : struct Node node*

  struct Node *p= &node[0];

  init(&p, Node_num);

  return 0;
}

void init(struct Node **node, int num) {
  for (int i = 0; i < num; i++) {
    (*(node) + i)->str = STR;
  }
};

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-7-31 13:12:23 | 显示全部楼层
哇,看来你在指针与数组的世界里遨游,遇到了一些小波折。让我来帮你解开这个谜团。

首先,我们来看看你第一段代码的问题。这段代码中有个函数 `init(struct Node **node, int num)`。根据定义,这个函数期望接收一个指向指针的指针(`struct Node **`),也就是说它希望传入的是个“指向指针的入口”,想象一下是个贵族家庭的继承关系,你得给出家族的家谱才能继承。

但在 `main` 函数中,你传入了 `&node`,而 `node` 是一个结构体而不是指针,所以 GCC 吐槽了:“我不能把一个结构体直接转换成‘指向指针的指针’,我们注定无法相爱!”所以就报错了。

而第二段代码就简单多了。这里你把 `init` 函数的参数改为了 `init(struct Node *node, int num)`,这意味着它接受的是一个 `Node` 结构体的指针。然后在 `main` 函数中,通过 `init(node, Node_num);` 调用的时候,编译器会愉快地看到你传递的是一个结构体的地址,这就没问题了。

总结一下:

1. **代码1的错误**:你传递了一个结构体的地址给需要指向指针的指针的函数。编译器不想跟你玩这个复杂的游戏了,选择了拒绝。
   
2. **代码2的成功**:你给的是一个结构体的指针,正好符合函数的要求,所以一切顺利。

所以,记住这个道理:指针和数组之间的关系,就像鱼和水,彼此依存,但也要当心别搞混了哦!希望这个幽默的小解释能让你更明白指针与数组之间的千丝万缕的联系!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-1 13:01:33 | 显示全部楼层
代码1报错分析:
在代码1中,init函数的参数类型是struct Node **node,意味着它期望接收一个指向结构体数组的指针的指针。然而,在main函数中,当你试图通过&node传递参数时,实际上你是在尝试将一个指向结构体数组的指针(即struct Node (*)[Node_num])传递给一个期待struct Node **的参数。这是因为node本身就已经是一个指针(指向数组的首元素),对它取地址得到的是一个指向整个数组的指针,而非指向指针的指针,因此类型不匹配,导致编译错误。
代码2正确原因:
在代码2中,你修改了init函数的参数类型为struct Node *node,现在它期望接收一个指向结构体的指针,这正好与数组node解引用后的类型相匹配。当你在main函数中直接传递node时,数组名node会自动转换为指向数组首元素的指针,即struct Node *。这样,类型匹配,编译器接受这样的参数传递,并且在执行时能够正确地遍历数组,给每个结构体的str成员赋值。
结论:
代码2之所以能成功编译并运行,是因为你正确地调整了函数参数类型以匹配实际传递的指针类型,从而避免了类型不匹配的错误。代码1的错误在于尝试传递了一个与函数参数类型不相符的指针。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-8-4 11:09:03 | 显示全部楼层
FishC 发表于 2024-7-31 13:12
哇,看来你在指针与数组的世界里遨游,遇到了一些小波折。让我来帮你解开这个谜团。

首先,我们来看看你 ...

可为什么一向不严谨的gcc为什么突然就这么严格了呢?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-4 11:09:10 | 显示全部楼层
风眠 发表于 2024-08-04 11:09
可为什么一向不严谨的gcc为什么突然就这么严格了呢?


哈哈,这个问题问得好!但别担心,GCC 一直都是个“严谨”的家伙,只是在某些情况下,它的严格程度会让人觉得自己像是在参加一次编程考试。

其实,GCC 和很多其他编译器一样,遵循 C 语言的标准。当你的代码不符合这些标准时,它就会发出警告或错误信息。用个通俗的比喻,我们就把 GCC 想象成一个认真负责的老师,在课堂上发现同学们抄错答案的时候,总是要举手提醒你:“哎,你这题错了,快改过来!”

在你第二段代码中,一切都符合 C 语言的标准,所以 GCC 很开心地编译通过了。而在第一段代码中,由于你传递了不匹配的参数类型,它就像是老师看到学生交了一个“奇怪的作业”,立刻给你打了个叉,给你一个错误提示,让你知道这个地方需要改正。

所以,GCC 的严格并不是突然间的,而是它一直以来对标准的坚持。更重要的是,它是在保护你,确保你的代码能够正确运行。毕竟,在程序的世界里,错了一行代码可能就会引发一场不可预知的“软件海啸”!所以,咱们就得乖乖听老师的话,确保传递的指针和数组是对的。

为了帮助你避免未来的波折,记得在使用指针和数组时,多看看它们的定义以及调用的参数类型哦!这样,GCC 就不会再对你皱眉头了!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-8-4 11:10:10 | 显示全部楼层
行客 发表于 2024-8-1 13:01
代码1报错分析:
在代码1中,init函数的参数类型是struct Node **node,意味着它期望接收一个指向结构体数 ...

那如果我要这么做,那么我应该怎么声明呢?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-4 11:10:23 | 显示全部楼层
风眠 发表于 2024-08-04 11:10
那如果我要这么做,那么我应该怎么声明呢?


好问题!如果你想在 `init` 函数中使用一个结构体数组或动态分配的结构体指针,你可以选择以下几种方法,取决于你希望如何管理这个结构体。

### 方法一:使用结构体数组

如果你想要传递一个结构体数组,你可以直接声明一个结构体数组并将其传递给 `init` 函数。这里有个例子:
#include <stdio.h>
#include <stdlib.h>

#define Node_num 1
#define STR '&'

struct Node {
    char str;
    int x, y;
};

void init(struct Node *node, int num);

int main(void) {
    struct Node nodes[Node_num]; // 声明一个结构体数组

    init(nodes, Node_num); // 传递结构体数组
    printf("Ok\n");

    return 0;
}

void init(struct Node *node, int num) {
    for (int i = 0; i < num; i++) {
        node[i].str = STR; // 直接访问数组元素
    }
}

### 方法二:使用指向结构体的指针(动态分配)

如果你希望动态分配内存以创建结构体数组,你可以使用 `malloc` 来分配内存,并将其传递给 `init` 函数:
#include <stdio.h>
#include <stdlib.h>

#define Node_num 1
#define STR '&'

struct Node {
    char str;
    int x, y;
};

void init(struct Node *node, int num);

int main(void) {
    struct Node *nodes = malloc(Node_num * sizeof(struct Node)); // 动态分配内存

    if (nodes == NULL) {
        fprintf(stderr, "内存分配失败!\n");
        return 1;
    }

    init(nodes, Node_num); // 传递动态分配的数组
    printf("Ok\n");

    free(nodes); // 释放分配的内存
    return 0;
}

void init(struct Node *node, int num) {
    for (int i = 0; i < num; i++) {
        node[i].str = STR; // 直接访问结构体指针
    }
}

### 关键点总结:
- 在方法一中,你直接声明了一个结构体数组,并把它作为参数传递给 `init` 函数。这种情况下,函数会得到一个指向数组首元素的指针。
- 在方法二中,你使用 `malloc` 动态分配了一块内存用于存储结构体数组,然后再将这个指针传递给函数。在使用完毕后,别忘了使用 `free` 释放内存,防止内存泄漏。

无论你选择哪种方式,都要确保在调用 `init` 函数的时候,传递的参数类型是匹配的,这样 GCC 就不会对你皱眉头了!希望这能帮助你更好地使用指针和数组!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-8 12:16:14 | 显示全部楼层    本楼为最佳答案   
风眠 发表于 2024-8-4 11:10
那如果我要这么做,那么我应该怎么声明呢?
 struct Node node[Node_num];

 init(&node, Node_num);

我们首先分析,对数组取地址,得到的是什么?

C语言标准规定,当数组名作为数组定义的标识符(也就是定义或声明数组时)、sizeof 或 & 的操作数时,它才表示整个数组本身,在其他的表达式中,数组名会被转换为指向第 0 个元素的指针(地址)。

也就是,&node得到的是数组的地址。

因此在编译器编译时,会出现类似错误:
error C2664: 'init' : cannot convert parameter 1 from 'struct Node (*)[1]' to 'struct Node ** '

你想得到的是数组内的一个具体元素的指针,然后以指针的形式,取进行赋值。

所以,先考虑如何得到这个数组元素的指针:
struct Node node[Node_num];
node即为第一个元素的指针。

所以,第一种方法:
#include <stdio.h>
#include <stdlib.h>

#define Node_num 1
#define STR '&'

struct Node {
  char str;
  int x, y;
};

void init(struct Node *node, int num);

int main(void) {
  struct Node node[Node_num];
  // node : struct Node node*

  init(node, Node_num);
  printf("Ok\n");

  return 0;
}

void init(struct Node *node, int num) {
  for (int i = 0; i < num; i++) {
    ((node) + i)->str = STR;
  }
};


如果非要用原帖子内的这模式来完成,那么可以改成
#include <stdio.h>
#include <stdlib.h>

#define Node_num 1
#define STR '&'

struct Node {
  char str;
  int x, y;
};

void init(struct Node **node, int num);

int main(void) {
  struct Node node[Node_num];
  // node : struct Node node*

  struct Node *p= &node[0];

  init(&p, Node_num);

  return 0;
}

void init(struct Node **node, int num) {
  for (int i = 0; i < num; i++) {
    (*(node) + i)->str = STR;
  }
};

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-8-9 09:08:56 | 显示全部楼层
行客 发表于 2024-8-8 12:16
我们首先分析,对数组取地址,得到的是什么?

C语言标准规定,当数组名作为数组定义的标识符(也 ...

明白了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-9-21 11:27

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表