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

相关推荐
Ajiang282473530421 分钟前
对于C++中stack和queue的认识以及priority_queue的模拟实现
开发语言·c++
幽兰的天空26 分钟前
Python 中的模式匹配:深入了解 match 语句
开发语言·python
Theodore_10223 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
网易独家音乐人Mike Zhou4 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
----云烟----5 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024065 小时前
SQL SELECT 语句:基础与进阶应用
开发语言
开心工作室_kaic6 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it6 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
武子康6 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
转世成为计算机大神6 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式