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

相关推荐
qq_433618442 分钟前
shell 编程(二)
开发语言·bash·shell
charlie11451419117 分钟前
C++ STL CookBook
开发语言·c++·stl·c++20
袁袁袁袁满17 分钟前
100天精通Python(爬虫篇)——第113天:‌爬虫基础模块之urllib详细教程大全
开发语言·爬虫·python·网络爬虫·爬虫实战·urllib·urllib模块教程
ELI_He99923 分钟前
PHP中替换某个包或某个类
开发语言·php
小林熬夜学编程28 分钟前
【Linux网络编程】第十四弹---构建功能丰富的HTTP服务器:从状态码处理到服务函数扩展
linux·运维·服务器·c语言·网络·c++·http
m0_7482361131 分钟前
Calcite Web 项目常见问题解决方案
开发语言·前端·rust
倔强的石头10639 分钟前
【C++指南】类和对象(九):内部类
开发语言·c++
Jackey_Song_Odd39 分钟前
C语言 单向链表反转问题
c语言·数据结构·算法·链表
Watermelo61743 分钟前
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
开发语言·前端·javascript·算法·数据挖掘·数据分析·ecmascript
A懿轩A2 小时前
C/C++ 数据结构与算法【数组】 数组详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·数组