穿越内存迷宫:C语言地址与指针的的冒险之旅

前言

C语言的魅力在于其直接的内存控制,而地址和指针是这种控制的核心。深入了解这些概念,将帮助我们更好地理解和利用C语言的潜力。本文将带领你踏上地址与指针的奇妙之旅,揭示它们在程序设计中的神秘面纱。

奇妙指针之旅:解码C语言中地址的秘密

文章目录

  • 前言
  • 奇妙指针之旅:解码C语言中地址的秘密
    • 示例与应用
      • 1. **基本定义和输出**
      • 2. **函数参数传递**
      • 3. **交换函数**
  • 地址和指针
    • 基础知识
      • 1. **变量和内存地址:**
      • 2. **指针的概念:**
      • 3. **使用指针访问数据:**
      • 4. **指针和数组:**
      • 5. **指针运算:**
      • 6. **空指针和野指针:**
      • 7. **指针和函数:**
    • 示例
      • 1. 基本定义和输出
        • 介绍:
      • 2. 函数 `fun_1`:按值传递参数
        • 介绍:
      • 3. 函数 `fun_2`:引用传递参数
        • 介绍:
      • 4. 函数 `fun_3`:指针传递参数
        • 介绍:
      • 5. 交换函数:引用方式
        • 介绍:
      • 6. 交换函数:指针方式
        • 介绍:
      • 7. 函数调用和输出
        • 介绍:
    • 总结

示例与应用

1. 基本定义和输出

演示如何定义变量、引用和指针,并打印它们的初始值和地址。

2. 函数参数传递

通过函数 fun_1fun_2fun_3 展示了按值、引用和指针传递参数的不同方式,以及它们对原始数据的影响。

3. 交换函数

展示了通过引用和指针方式交换两个整数值的函数,突显了引用和指针在函数中的实际运用。

地址和指针

基础知识

当我们谈到C语言中的地址和指针时,我们实际上在讨论如何有效地管理和操作计算机内存。让我们从基础开始:

1. 变量和内存地址:

在C语言中,变量是程序中用于存储数据的标识符。每个变量都有一个关联的内存地址,这是它在计算机内存中的位置。

int num = 42;

在这个例子中,num 是一个整数变量,它存储了值 42,并且在内存中有一个地址,我们可以通过 & 操作符获取这个地址:

printf("变量num的地址是:%p", &num);

2. 指针的概念:

指针是一种特殊类型的变量,它存储的不是值本身,而是一个地址。通过指针,我们可以直接访问和修改内存中的数据。

int *ptr; // 定义一个整数型指针
ptr = # // 将指针指向变量num的地址

在这个例子中,ptr 是一个整数型指针,通过 &num 将它指向了变量 num 的地址。

3. 使用指针访问数据:

一旦我们有了指针,我们可以通过解引用操作符 * 来访问指针所指向的内存中的值。

printf("通过指针访问的值是:%d", *ptr);

这将输出 42,因为指针 ptr 指向了存储 num 的内存地址,通过 *ptr 我们得到了这个地址上的值。

4. 指针和数组:

指针和数组在C语言中密切相关。数组名本质上就是一个指针,它存储了数组第一个元素的地址。

int arr[3] = {10, 20, 30};
int *arrPtr = arr; // 数组名arr就是指向数组第一个元素的指针

printf("第一个元素的值:%d", *arrPtr);

5. 指针运算:

指针可以进行简单的算术运算。例如,通过增加指针的值,我们可以让指针指向下一个元素。

int arr[3] = {10, 20, 30};
int *ptr = arr;

printf("第一个元素:%d\n", *ptr); // 输出第一个元素
ptr++; // 指针移动到下一个元素
printf("移动后的元素:%d", *ptr); // 输出移动后的元素

6. 空指针和野指针:

空指针是指不指向任何有效内存地址的指针。野指针是指指向未知或无效地址的指针。在使用指针之前,务必确保它指向有效的内存。

int *nullPtr = NULL; // 空指针
int *wildPtr; // 野指针,未初始化的指针

7. 指针和函数:

指针也可以作为函数参数,通过引用传递可以修改原始数据。

void increment(int *x) {
    (*x)++;
}

int main() {
    int num = 5;
    increment(&num);
    printf("增加后的值:%d", num);
    return 0;
}

这是一个简单的介绍,C语言中指针的使用非常广泛,它们为程序员提供了更多的控制和灵活性,但也需要小心使用,以避免潜在的错误和内存泄漏。

示例

1. 基本定义和输出

#include <stdio.h>

int main() {
    // 定义整数变量 x,引用 b,指针 p
    int x = 0;
    int &b = x; // 引用 b 是 x 的别名
    int *p = &x; // 指针 p 存储 x 的地址

    // 打印初始值和地址
    printf("Initial Values:\n");
    printf("x: %d\n", x);
    printf("&x: %p\n", (void *)&x);
    printf("b: %d\n", b);
    printf("&b: %p\n", (void *)&b);
    printf("*p: %d\n", *p);
    printf("p: %p\n", (void *)p);

    return 0;
}
介绍:
  • 在这个部分,我们定义了一个整数变量 x,一个引用 b,和一个指向整数的指针 p
  • 引用 bx 的别名,指针 p 存储了 x 的地址。
  • 打印了变量 x、引用 b、指针 p 的值和地址。
    在这里插入图片描述

2. 函数 fun_1:按值传递参数

#include <stdio.h>

// 函数 fun_1 接受整数按值传递,修改不影响调用者
void fun_1(int a) {
    a = 5;
}

int main() {
    int x = 10;

    // 打印调用前的值
    printf("Before fun_1: %d\n", x);

    // 调用 fun_1
    fun_1(x);

    // 打印调用后的值
    printf("After fun_1: %d\n", x);

    return 0;
}
介绍:
  • fun_1 是一个函数,接受整数参数 a
  • 由于参数是按值传递的,对 a 的修改不会影响调用者的变量。
  • 在主函数中,定义了整数变量 x,打印了调用 fun_1 前后的值,以验证 fun_1x 的影响。
    在这里插入图片描述

3. 函数 fun_2:引用传递参数

#include <stdio.h>

// 函数 fun_2 接受整数引用,修改影响调用者
void fun_2(int &a) {
    a = 5;
}

int main() {
    int x = 10;

    // 打印调用前的值
    printf("Before fun_2: %d\n", x);

    // 调用 fun_2
    fun_2(x);

    // 打印调用后的值
    printf("After fun_2: %d\n", x);

    return 0;
}
介绍:
  • fun_2 是一个函数,接受整数引用 a
  • 由于引用是传址的,对 a 的修改会直接影响调用者的变量。
  • 在主函数中,定义了整数变量 x,打印了调用 fun_2 前后的值,以验证 fun_2x 的影响。
    在这里插入图片描述

4. 函数 fun_3:指针传递参数

#include <stdio.h>

// 函数 fun_3 接受整数指针,通过指针修改调用者的值
void fun_3(int *a) {
    *a = 5;
}

int main() {
    int x = 10;

    // 打印调用前的值
    printf("Before fun_3: %d\n", x);

    // 调用 fun_3
    fun_3(&x);

    // 打印调用后的值
    printf("After fun_3: %d\n", x);

    return 0;
}
介绍:
  • fun_3 是一个函数,接受整数指针 a
  • 通过指针修改 *a 的值,实际上是修改了指针指向的地址上的值。
  • 在主函数中,定义了整数变量 x,打印了调用 fun_3 前后的值,以验证 fun_3x 的影响。
    在这里插入图片描述

5. 交换函数:引用方式

#include <stdio.h>

// 通过引用交换两个整数的值
void swapByReference(int &a, int &b) {
    int temp = a;
    a = b;
    b = temp;
}

int main() {
    int x = 5;
    int y = 10;

    // 打印交换前的值
    printf("Before swapByReference: x=%d, y=%d\n", x, y);

    // 调用交换函数
    swapByReference(x, y);

    // 打印交换后的值
    printf("After swapByReference: x=%d, y=%d\n", x, y);

    return 0;
}
介绍:
  • swapByReference 是一个通过引用交换两个整数值的函数。
  • 使用了一个辅助变量 temp,通过引用直接修改了传入的两个变量的值。
  • 在主函数中,定义了两个整数变量 xy,打印了交换前后的值,以验证 swapByReference 的效果。
    在这里插入图片描述

6. 交换函数:指针方式

#include <stdio.h>

// 通过指针交换两个整数的值
void swapByPointer(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main() {
    int x = 5;
    int y = 10;

    // 打印交换前的值
    printf("Before swapByPointer: x=%d, y=%d\n", x, y);
    // 调用交换函数
    swapByPointer(&x, &y);

    // 打印交换后的值
    printf("After swapByPointer: x=%d, y=%d\n", x, y);

    return 0;
}
介绍:
  • swapByPointer 是一个通过指针交换两个整数值的函数。
  • 使用了一个辅助变量 temp,通过指针直接修改了传入的两个变量的值。
  • 在主函数中,定义了两个整数变量 xy,打印了交换前后的值,以验证 swapByPointer 的效果。
    在这里插入图片描述

7. 函数调用和输出

#include <stdio.h>

int main() {
    int x = 10;
    int &b = x; // 引用 b 是 x 的别名
    int *p = &x; // 指针 p 存储 x 的地址

    // 调用函数和交换函数
    fun_1(x);
    printf("\nAfter fun_1:\n");
    printf("x: %d\n", x);

    fun_2(x);
    printf("\nAfter fun_2:\n");
    printf("x: %d\n", x);

    fun_3(&x);
    printf("\nAfter fun_3:\n");
    printf("x: %d\n", x);

    // 使用引用和指针交换值
    swapByReference(x, b);
    printf("\nAfter swapByReference:\n");
    printf("x: %d\n", x);

    swapByPointer(&x, p);
    printf("\nAfter swapByPointer:\n");
    printf("x: %d\n", x);

    return 0;
}
介绍:
  • 主函数中调用了前面介绍的各个函数和交换函数。
  • 打印了调用函数和交换函数后的变量值。

总结

掌握C语言中的地址与指针是提升编程技能的关键一步。地址与指针不仅仅是内存管理的工具,更是解锁程序性能和灵活性的钥匙。通过学习本文提供的知识,你将能够更自信、更精通地应对C语言编程中的各种挑战。

在这场奇妙的指针之旅中,我们将穿越C语言内存的迷宫,揭示地址与指针的神奇力量。无论你是初学者还是有经验的开发者,本文将为你打开一扇通向C语言深奥世界的大门。准备好迎接挑战,一同探索指针的魔法!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/132466.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

日语形容词分类

かっこいい的否定变形是かっこよくない

Selenium自动化测试细节讲解

与以前瀑布式开发模式不同&#xff0c;现在软件测试人员具有使用自动化工具执行测试用例套件的优势&#xff0c;而以前&#xff0c;测试人员习惯于通过测试脚本执行来完成测试。 但自动化测试的目的不是完全摆脱手动测试&#xff0c;而是最大程度地减少手动运行的测试。自动化…

计算机毕业设计选题推荐-农产品销售微信小程序/安卓APP-项目实战

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

抖音小程序开发:打造高效餐饮团购平台的技术指南

在餐饮行业&#xff0c;通过抖音小程序开发一个高效的团购平台&#xff0c;可以为餐厅提供更广泛的曝光&#xff0c;增加销售机会。本文将从技术角度出发&#xff0c;为您提供一份详细的抖音小程序开发指南&#xff0c;助您打造一流的餐饮团购平台。 一、确定需求和功能 在开…

让各大运营商都默默流泪的 HTTPS 协议(HTTPS 的加密流程)

文章目录 前言1. 什么是 HTTPS1.1 臭名昭著的 "运营商劫持" 2. 什么是"加密"3. HTTPS 的加密流程3.1 对称加密用对称加密可行吗&#xff1f; 3.2 引入非对称加密用对称加密非对称加密可行吗&#xff1f; 3.3 中间人攻击如何证明浏览器收到的公钥一定是该网…

栈 和 队列

什么是栈? 一种特殊的线性表&#xff0c;只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出&#xff08;LIFO - Last In First Out&#xff09;的原则。   从数据结构的角度来看&…

【图文详解】Android Studio(新版本) 配置OpenCV库,解决出现的各种问题

前言 写这篇文章的目的就是记录自己在配置OpenCV库时遇到的问题。在网上查找相关资料时&#xff0c;发现很多Android Studio都是老版本&#xff0c;并且出现的问题都不能被解决。自己在配置过程中出现的问题都进行记录下来并一一解决。 新建项目 点击 New Project 选择界面 …

STM32F4X SDIO(九) 例程讲解-SD卡擦除、读写

STM32F4X SDIO &#xff08;九&#xff09; 例程讲解-SD卡擦除、读写 例程讲解-SD卡擦除、读写SD卡擦除CMD32:ERASE_WR_BLK_START命令发送命令响应 CMD33:ERASE_WR_BLK_END命令发送命令响应CMD38:ERASE命令响应 CMD13:SD_CMD_SEND_STATUS命令发送命令回应 SD卡读数据CMD16:SET_…

【LeetCode】挑战100天 Day10(热题+面试经典150题)

【LeetCode】挑战100天 Day10&#xff08;热题面试经典150题&#xff09; 一、LeetCode介绍二、LeetCode 热题 HOT 100-122.1 题目2.2 题解 三、面试经典 150 题-123.1 题目3.2 题解 一、LeetCode介绍 LeetCode是一个在线编程网站&#xff0c;提供各种算法和数据结构的题目&…

matplotlib 设置标签和图例

常用标签 xlabel&#xff1a;x轴标签名称。 ylabel&#xff1a;y轴标签名称。 title&#xff1a;图像标题。 设置x和y轴的刻度&#xff1a;xticks和yticks。 nums np.arange(0, 1.3, 0.01)# 设置标题 plt.title("title") # 设置横坐标信息 plt.xlabel("x-…

复杂度计算实例

1.常见时间复杂度计算举例 实例1 实例1基本操作执行了2N10次&#xff0c;通过推导大O阶方法知道&#xff0c;时间复杂度为 O(N) 实例2 实例2基本操作执行了MN次&#xff0c;有两个未知数M和N&#xff0c;时间复杂度为 O(NM) 实例3 实例3基本操作执行了100次&#xff0c;通过…

C++学习笔记(二):C++是如何运行的

C是如何运行的 include 预处理语句&#xff0c;在编译前就会被处理。 main函数 程序入口。 #include <iostream>int main() {std::cout << "Hello World!" << std::endl;std::cin.get();return 0; }Visual Studio 解决方案平台指的是编译的代码的…

探索微信小程序框架的精华——高质量的优秀选择

目录 引言&#xff1a; 1. 框架性能 2. 开发者工具支持 3. 文档和社区支持 4. 扩展能力 5. 使用率和稳定性 结语&#xff1a; 引言&#xff1a; 微信小程序作为一种轻量级、高效便捷的应用形式&#xff0c;已经在移动应用领域占据了重要地位。而其中&#xff0c;选择一个…

Nussbaumer Transform 以及 Amortized FHEW bootstrapping

参考文献&#xff1a; [Nuss80] Nussbaumer H. Fast polynomial transform methods for multidimensional DFTs[C]//ICASSP’80. IEEE International Conference on Acoustics, Speech, and Signal Processing. IEEE, 1980, 5: 235-237.[SV11] Smart N P, Vercauteren F. Full…

C++ 配合图形库实现画线效果

#include<stdio.h> #include <conio.h> #include<math.h> #include <graphics.h> // 引用图形库头文件 #define N 12 int List[N][N];void draw() {for (int i 0; i < N; i) {int x 200 * cos(2 * 3.14 * i / N);int y 200 * sin(2 * 3.1…

归并排序 merge Sort + 图解 + 递归 / 非递归

归并排序(merge sort)的主要思想是&#xff1a;将若干个有序序列逐步归并&#xff0c;最终归并为一个有序序列二路归并排序(2-way merge sort)是归并排序中最简单的排序方法 &#xff08;1&#xff09;二路归并排序的递归实现 // 二路归并排序的递归实现 void merge(vector&l…

Ocelot:.NET开源API网关提供路由管理、服务发现、鉴权限流等功能

随着微服务的兴起&#xff0c;API网关越来越常见。API网关是连接应用程序和用户之间的桥梁&#xff0c;就像一个交通指挥员&#xff0c;负责处理所有进出应用的数据和请求&#xff0c;确保安全、高效、有序地流通。 今天给大家推荐一个.NET开源API网关。 01 项目简介 Ocelot…

家居美学:将水离子壁炉融入你的现代装饰

当谈及家居装饰和壁炉选择时&#xff0c;水离子雾化壁炉是一个备受瞩目的话题。水离子雾化壁炉的美学价值&#xff0c;还为室内装饰带来全新的维度。它甚至能够激发室内装饰的灵感。 水离子雾化壁炉是现代美学的标志&#xff0c;融合了简洁、线条清晰的设计。这种壁炉常常采用不…

osg点云加载与渲染

目录 效果 laslib 关键代码 完整代码 效果 las点云读取使用了laslib这个库。 laslib 关键代码 {// 这里演示读取一个 .txt 点云文件const char* lasfile path.c_str();std::ifstream ifs;ifs.open(lasfile, std::ios::in | std::ios::binary);liblas::ReaderFactory f;libl…

给CAD中添加自定义菜单CUIX

本文以AutoCAD2020为例&#xff0c;介绍如何添加自定义菜单。 打开AutoCAD2020&#xff0c;在命令行执行CUI并回车&#xff0c;出现菜单 进入菜单编辑界面 点击传输&#xff0c;然后新建 在菜单上右键&#xff0c;添加自定义菜单 点击保存&#xff0c;即可存为cuix文件。之后…