C语言之*与&

* 符号的两个主要的含义

在声明变量时,* 表示该变量是一个指针。

例如: int *ptr; 表示 ptr 是一个指向 int 类型数据的指针。

在使用指针时,* 用于间接访问指针所指向的内存地址中的值。

例如: *ptr = 10; 表示将值 10 赋给 ptr 所指向的内存地址。

当出现两个 ** 时,它表示指向指针的指针,也就是二级指针。

例如: int **pptr; 表示 pptr 是一个指向 int * 类型数据的指针,也就是一个指向指针的指针。

二级指针的使用场景包括:

在函数中传递指针参数,并在函数内部修改指针的值。

处理动态分配的二维数组。

实现链表、树等复杂的数据结构。

例子
c 复制代码
int main() {
    int x = 10;
    int *p = &x;   // p 是一个指向 int 类型数据的指针
    int **pp = &p; // pp 是一个指向 int* 类型数据的指针,也就是一个二级指针

    printf("x = %d\n", x);       // 输出: x = 10
    printf("*p = %d\n", *p);     // 输出: *p = 10
    printf("**pp = %d\n", **pp); // 输出: **pp = 10
    
    **pp = 20;
    printf("x = %d\n", x);       // 输出: x = 20
    
    return 0;
}

在这个例子中:

我们首先声明了一个整型变量 x 并赋值为 10。

然后声明了一个指向 int 型变量的指针 p,并让它指向 x。

接下来声明了一个二级指针 pp,它指向指针 p。

现在来看这一行代码:

c 复制代码
**pp = 20;

这行代码的执行过程如下:

首先通过 pp 找到它所指向的内存地址,也就是 p 的地址。

然后通过 *pp(解引用 pp)得到 p 的值,也就是 x 的地址。

最后通过 **pp(二次解引用 pp)得到 x 的值,并将其赋值为 20。

所以,当我们执行 **pp = 20; 时,实际上是在修改 x 的值,而不是 p 或 pp 本身。

这就是为什么在最后的 printf("x = %d\n", x); 语句中,x 的值变成了 20。

小结

总结一下,当我们使用二级指针 **pp 时,实际上是通过两次间接寻址,最终操作的是 x 这个变量本身。因此,修改 **pp 的值就相当于直接修改了 x 的值。

& 的主要意义

在 C 语言中,& 符号用于获取元素的内存地址操作,它的主要用途包括:

获取变量的地址

例如: int x = 10; int *p = &x; 这里 &x 表示获取变量 x 的内存地址,并将其赋值给指针变量 p。

作为函数参数,实现按引用传递

例如: void swap(int *a, int *b) { ... } 函数中的 int *a 和 int *b 就是指针参数,可以使用 & 操作符将变量的地址传递给它们,从而在函数内部修改变量的值。

取数组元素的地址

例如: int arr[] = {1, 2, 3}; int *p = &arr[0]; 这里 &arr[0] 表示获取数组 arr 的第一个元素的地址,并赋值给指针 p。

获取结构体成员的地址

例如: struct Person { int age; char name[20]; }; struct Person p; int *age_ptr = &p.age; 这里 &p.age 表示获取结构体变量 p 的 age 成员的地址。

code实例

c 复制代码
#include <stdio.h>
#include <stdlib.h>

// 动态数组结构体
typedef struct {
    int *data;  // 指向数据的指针
    int size;   // 数组大小
} DynamicArray;

// 初始化动态数组
DynamicArray* init_dynamic_array() {
    DynamicArray *arr = (DynamicArray*)malloc(sizeof(DynamicArray));
    arr->data = NULL;
    arr->size = 0;
    return arr;
}

// 向动态数组中添加元素
void add_element(DynamicArray *arr, int value) {
    // 分配新的内存空间
    arr->data = (int*)realloc(arr->data, (arr->size + 1) * sizeof(int));
    // 将新元素添加到数组末尾
    arr->data[arr->size] = value;
    arr->size++;
}

// 获取动态数组中的元素
int get_element(DynamicArray *arr, int index) {
    // 检查索引是否越界
    if (index < 0 || index >= arr->size) {
        printf("Error: Index out of bounds.\n");
        return 0;
    }
    // 返回指定索引的元素
    return arr->data[index];
}

int main() {
    // 初始化动态数组
    DynamicArray *arr = init_dynamic_array();

    // 向动态数组中添加元素
    add_element(arr, 10);
    add_element(arr, 20);
    add_element(arr, 30);

    // 获取动态数组中的元素
    printf("Element at index 0: %d\n", get_element(arr, 0));
    printf("Element at index 1: %d\n", get_element(arr, 1));
    printf("Element at index 2: %d\n", get_element(arr, 2));

    // 释放动态数组占用的内存
    free(arr->data);
    free(arr);

    return 0;
}

在这个例子中,我们定义了一个 DynamicArray 结构体,它包含一个指向数据的指针 data 和一个表示数组大小的整型变量 size。

我们实现了三个函数:

docs 复制代码
init_dynamic_array():初始化一个动态数组,分配内存并设置初始大小为 0。
add_element():向动态数组中添加一个新元素。它首先使用 realloc() 函数扩展数组的内存空间,然后将新元素添加到数组末尾。
get_element():获取动态数组中指定索引的元素。它会先检查索引是否越界,然后返回相应的元素值。
在 main() 函数中,我们演示了如何使用这些函数来创建、添加元素和获取元素。

值得注意的是,我们使用了指针 data 来动态分配和管理数组的内存空间。在最后,我们需要手动释放 data 指针和 DynamicArray 结构体占用的内存,以避免内存泄漏。

小结

总的来说,& 操作符是 C 语言中一个非常重要的符号,它允许我们获取变量、数组元素、结构体成员等的内存地址,从而可以使用指针来操作它们。这在很多场景下非常有用,特别是在涉及内存管理、函数参数传递等方面。

相关推荐
序属秋秋秋43 分钟前
《C++初阶之内存管理》【内存分布 + operator new/delete + 定位new】
开发语言·c++·笔记·学习
ruan1145142 小时前
MySQL4种隔离级别
java·开发语言·mysql
quant_19863 小时前
R语言如何接入实时行情接口
开发语言·经验分享·笔记·python·websocket·金融·r语言
啟明起鸣6 小时前
【网络编程】简易的 p2p 模型,实现两台虚拟机之间的简单点对点通信,并以小见大观察 TCP 协议的具体运行
c语言·网络·tcp/ip·p2p
百锦再7 小时前
详细解析 .NET 依赖注入的三种生命周期模式
java·开发语言·.net·di·注入·模式·依赖
风吹落叶花飘荡7 小时前
2025 Next.js项目提前编译并在服务器
服务器·开发语言·javascript
失败又激情的man8 小时前
python之requests库解析
开发语言·爬虫·python
专注VB编程开发20年8 小时前
常见 HTTP 方法的成功状态码200,204,202,201
开发语言·网络协议·tcp/ip·http
有没有没有重复的名字8 小时前
线程安全的单例模式与读者写者问题
java·开发语言·单例模式
开开心心_Every9 小时前
便捷的电脑自动关机辅助工具
开发语言·人工智能·pdf·c#·电脑·音视频·sublime text