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

相关推荐
VBA63373 分钟前
VBA数据库解决方案第十五讲:Recordset集合中单个数据的精确处理
开发语言
wrx繁星点点6 分钟前
事务的四大特性(ACID)
java·开发语言·数据库
不写八个13 分钟前
Python办公自动化教程(005):Word添加段落
开发语言·python·word
HEX9CF17 分钟前
【CTF Web】Pikachu xss之href输出 Writeup(GET请求+反射型XSS+javascript:伪协议绕过)
开发语言·前端·javascript·安全·网络安全·ecmascript·xss
赵荏苒42 分钟前
Python小白之Pandas1
开发语言·python
丶Darling.44 分钟前
代码随想录 | Day26 | 二叉树:二叉搜索树中的插入操作&&删除二叉搜索树中的节点&&修剪二叉搜索树
开发语言·数据结构·c++·笔记·学习·算法
人生の三重奏1 小时前
前端——js补充
开发语言·前端·javascript
平凡的小码农1 小时前
JAVA实现大写金额转小写金额
java·开发语言
yttandb1 小时前
重生到现代之从零开始的C语言生活》—— 内存的存储
c语言·开发语言·生活
我明天再来学Web渗透2 小时前
【hot100-java】【二叉树的层序遍历】
java·开发语言·数据库·sql·算法·排序算法