C语言指针专题一 -- 指针基础原理

目录

1. 指针概念

地址和变量

指针

2. 指针的声明与初始化

 3. 指针的使用

指针访问

指针的运算

 指针与数组

指针与函数

4. 编程实例

5. 指针的常见陷阱与防御

6. 总结 


 

1. 指针概念

地址和变量

在C语言中,地址和变量是两个基本但非常重要的概念。

1. 变量是指程序中用于存储数据值的命名位置。每个变量都有一个特定的数据类型,这决定了它可以存储的数据种类(如整数、字符、浮点数等)以及需要分配多少内存空间。创建变量时,系统会在计算机的内存中为该变量分配一块空间,并将你选择的名字与这块空间关联起来。之后,你可以通过这个名字来访问或修改这块内存中的数据。

int age = 25;

这里age就是一个变量,它的类型是int,表示它存储的是一个整数值。在这个例子中,age被初始化为25。

2. 地址指的是内存中的具体位置。当你声明一个变量时,系统会为其分配一定的内存空间,而这个空间的起始位置就是该变量的地址。可以通过取地址运算符&来获取变量的地址。地址是一个非常关键的概念,尤其是在处理指针时。指针是一种特殊的变量,它存储的是另一个变量或函数的地址,而不是直接存储数据值。

int age = 25;
printf("变量age的地址: %p", (void*)&age);


这段代码打印出变量age的地址。注意这里的(void*)是为了确保地址以正确的格式输出;在C语言中,使用%p格式说明符来打印指针(地址)。

变量是你用来命名并存储数据的地方。每个变量都有其特定的数据类型,并占用一定数量的内存。地址则是这些变量在内存中的具体位置。

指针

  • 指针变量:指针变量是用来存储内存地址的变量。指针变量的类型决定了它所指向的数据类型。

  • 地址运算符&:用于获取变量的内存地址。

  • 间接寻址运算符*:用于访问指针所指向的内存地址中的数据。

指针指向的内存区域中的数据称为指针的目标。

2. 指针的声明与初始化

指针的声明格式如下:

数据类型 *指针变量名;

例如:

int *p;  // 声明一个指向int类型数据的指针p

 指针的初始化通常是通过将某个变量的地址赋值给指针:

int a = 10;
int *p = &a;  // 将变量a的地址赋值给指针p

 3. 指针的使用

指针访问

通过指针可以访问和修改它所指向的变量的值:

int a = 10;
int *p = &a;
*p = 20;  // 通过指针p修改a的值为20

指针的运算

指针可以进行加减运算,运算的结果是指针向前或向后移动若干个元素的位置。指针的运算通常用于数组操作。

int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;  // p指向数组的第一个元素
p++;  // p现在指向数组的第二个元素

 指针与数组

数组名本身就是一个指针,它指向数组的第一个元素。数组的指针是指数组在内存中的起始地址,数组元素的地址是指数组元素在内存中的起始地址。

通过指针可以遍历数组:

int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;
for (int i = 0; i < 5; i++) {printf("%d ", *(p + i));  // 输出数组的每个元素
}

假定指针变量px的地址值等于数组指针x(即指针变量px指向数组的首元数),则:x[i] 、*(px+i)、*(x+i) 和px[i]具有完全相同的功能:访问数组第i+1个数组元素。

指针与函数

指针可以作为函数的参数,使得函数能够修改实参的值:

void increment(int *p) {(*p)++;  // 通过指针修改实参的值
}int main() {int a = 10;increment(&a);  // 传递a的地址printf("%d", a);  // 输出11return 0;
}

4. 编程实例

实例1:使用指针交换两个变量的值

#include <stdio.h>void swap(int *a, int *b) {int temp = *a;*a = *b;*b = temp;
}int main() {int x = 10, y = 20;printf("Before swap: x = %d, y = %d\n", x, y);swap(&x, &y);printf("After swap: x = %d, y = %d\n", x, y);return 0;
}

 实例2:使用指针遍历数组

#include <stdio.h>int main() {int arr[5] = {1, 2, 3, 4, 5};int *p = arr;for (int i = 0; i < 5; i++) {printf("%d ", *(p + i));}return 0;
}

 实例3:使用指针作为函数参数修改数组元素

#include <stdio.h>void modifyArray(int *arr, int size) {for (int i = 0; i < size; i++) {arr[i] *= 2;  // 将数组中的每个元素乘以2}
}int main() {int arr[5] = {1, 2, 3, 4, 5};modifyArray(arr, 5);for (int i = 0; i < 5; i++) {printf("%d ", arr[i]);}return 0;
}

实例4:函数指针实现排序策略

#include <stdio.h>// 比较函数类型
typedef int (*CompareFunc)(int, int);void bubbleSort(int arr[], int n, CompareFunc compare) {for (int i=0; i<n-1; i++) {for (int j=0; j<n-i-1; j++) {if (compare(arr[j], arr[j+1]) > 0) {int temp = arr[j];arr[j] = arr[j+1];arr[j+1] = temp;}}}
}int ascending(int a, int b) { return a - b; }  // 升序
int descending(int a, int b) { return b - a; } // 降序int main() {int arr[] = {5, 2, 8, 1, 3};int n = sizeof(arr)/sizeof(arr[0]);// 使用升序排序bubbleSort(arr, n, ascending);for (int i=0; i<n; i++) printf("%d ", arr[i]); // 输出1 2 3 5 8// 使用降序排序bubbleSort(arr, n, descending);printf("\n");for (int i=0; i<n; i++) printf("%d ", arr[i]); // 输出8 5 3 2 1return 0;
}

5. 指针的常见陷阱与防御

  1. 野指针(Dangling Pointer)

    • 指向已释放内存的指针,访问会导致未定义行为。

    • 防御:释放后立即置空指针。

      int *p = (int*)malloc(sizeof(int));
      free(p);
      p = NULL; // 防止野指针
  2. 内存泄漏

    • 分配内存后未释放。

    • 防御:确保每个malloc都有对应的free

  3. 越界访问

    • 指针操作超出合法内存范围。

    • 防御:严格检查指针偏移量。

6. 总结 

指针是C语言中非常强大的工具,它允许直接操作内存地址,提供了灵活的数据访问和操作方式。通过指针,可以实现高效的数据处理、动态内存管理以及复杂的数据结构(如链表、树等)。然而,指针的使用也需要谨慎,因为不当的指针操作可能导致程序崩溃或内存泄漏等问题。,每一个字节单元,都有一个编号,称为地址

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Python】已解决:ModuleNotFoundError: No module named ‘cv2’

个人简介&#xff1a;某不知名博主&#xff0c;致力于全栈领域的优质博客分享 | 用最优质的内容带来最舒适的阅读体验&#xff01;文末获取免费IT学习资料&#xff01; &#x1f345; 文末获取更多信息 &#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅收藏 &#x…

从0开始,来看看怎么去linux排查Java程序故障

一&#xff0c;前提准备 最基本前提&#xff1a;你需要有liunx环境&#xff0c;如果没有请参考其它文献在自己得到local建立一个虚拟机去进行测试。 有了虚拟机之后&#xff0c;你还需要安装jdk和配置环境变量 1. 安装JDK&#xff08;以OpenJDK 17为例&#xff09; 下载JDK…

设计模式-建造者模式、原型模式

目录 建造者模式 定义 类图 优缺点 角色 建造者模式和工厂模式比较 使用案例 原型模式 定义 类图 优缺点 应用场景 应用类型 浅克隆 深克隆 建造者模式 定义 将一个复杂的对象的构造与它的表示分离&#xff0c;使同样的构建过程可以创建不同的表示&#xff0c;…

1 HDFS

1 HDFS 1. HDFS概述2. HDFS架构3. HDFS的特性4. HDFS 的命令行使用5. hdfs的高级使用命令6. HDFS 的 block 块和副本机制6.1 抽象为block块的好处6.2 块缓存6.3 hdfs的文件权限验证6.4 hdfs的副本因子 7. HDFS 文件写入过程&#xff08;非常重要&#xff09;7.1 网络拓扑概念7.…

75-《倒提壶》

倒提壶 倒提壶&#xff08;学名&#xff1a;Cynoglossum amabile Stapf et Drumm.&#xff09;&#xff1a;紫草科&#xff0c;琉璃草属多年生草本植物&#xff0c;高可达60厘米。茎密生贴伏短柔毛。基生叶&#xff0c;长圆状披针形或披针形&#xff0c;茎生叶长圆形或披针形&a…

第一个3D程序!

运行效果 CPP #include <iostream> #include <fstream> #include <string> #include <cmath>#include <GL/glew.h> #include <GLFW/glfw3.h> #include <glm/glm.hpp> #include <glm/gtc/type_ptr.hpp> #include <glm/gtc/…

简要介绍C语言/C++的三目运算符

三元运算符是C语言和C中的一种简洁的条件运算符&#xff0c;它的形式为&#xff1a; 条件表达式 ? 表达式1 : 表达式2; 三元运算符的含义 条件表达式&#xff1a;这是一个布尔表达式&#xff0c;通常是一个比较操作&#xff08;如 >、<、 等&#xff09;。 表达式1&am…

本地部署DeepSeekp R1教程

目录 一.打开ollama官网&#xff0c;下载安装 1.下载完成双击安装程序 2.winr 输入cmd打开命令行输入命令 查看是否安装成功 二.部署DeepSeek R1模型 1. 下载模型&#xff1a;终端输入 (根据你的显存大小选择版本&#xff0c;16g就可以选择14b/32b)**电脑配置很低的话选…

事务04之死锁,锁底层和隔离机制原理

死锁和事务底层原理 文章目录 死锁和事务底层原理一&#xff1a;MySQL中的死锁现象1&#xff1a;何为死锁1.1&#xff1a;死锁的概念1.2&#xff1a;死锁产生的四个必要条件&#xff1a; 2&#xff1a;MySQL的死锁2.1&#xff1a;死锁的触发2.2&#xff1a;MySQL的死锁如何解决…

Fiddler(一) - Fiddler简介_fiddler软件

文章目录 一、为什么选择Fiddler作为抓包工具? 二、什么是Fiddler?三、Fiddler使用界面简介四、延伸阅读 一、为什么选择Fiddler作为抓包工具? 抓包工具有很多&#xff0c;小到最常用的web调试工具firebug&#xff0c;大到通用性强大的抓包工具wireshark。为什么使用fid…

RabbitMQ模块新增消息转换器

文章目录 1.目录结构2.代码1.pom.xml 排除logging2.RabbitMQConfig.java3.RabbitMQAutoConfiguration.java 1.目录结构 2.代码 1.pom.xml 排除logging <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/PO…

win11 sourcetree安装问题

win11 sourcetree安装出现msys-2.0.dll 问题&#xff0c;需要从win10的以下路径复制出 msys-2.0.dll来加入到win11中 C:\Users\kz121468\AppData\Local\Atlassian\SourceTree\git_local\usr\bin\ 复制到 win11的 C:\Users\kz121468\AppData\Local\Atlassian\SourceTree\git_lo…

Qt事件处理:理解处理器、过滤器与事件系统

1. 事件 事件 是一个描述应用程序中、发生的某些事情的对象。 在 Qt 中&#xff0c;所有事件都继承自 QEvent &#xff0c;并且每个事件都有特定的标识符&#xff0c;如&#xff1a;Qt::MouseButtonPress 代表鼠标按下事件。 每个事件对象包含该事件的所有相关信息&#xff…

一文读懂 Faiss:开启高维向量高效检索的大门

一、引言 在大数据与人工智能蓬勃发展的当下&#xff0c;高维向量数据如潮水般涌现。无论是图像、音频、文本&#xff0c;还是生物信息领域&#xff0c;都离不开高维向量来精准刻画数据特征。然而&#xff0c;在海量的高维向量数据中进行快速、准确的相似性搜索&#xff0c;却…

Openfga 授权模型搭建

1.根据项目去启动 配置一个 openfga 服务器 先创建一个 config.yaml文件 cd /opt/openFGA/conf touch ./config.yaml 怎么配置&#xff1f; 根据官网来看 openfga/.config-schema.json at main openfga/openfga GitHub 这里讲述详细的每一个配置每一个类型 这些配置有…

赛博算卦之周易六十四卦JAVA实现:六幺算尽天下事,梅花化解天下苦。

佬们过年好呀~新年第一篇博客让我们来场赛博算命吧&#xff01; 更多文章&#xff1a;个人主页 系列文章&#xff1a;JAVA专栏 欢迎各位大佬来访哦~互三必回&#xff01;&#xff01;&#xff01; 文章目录 #一、文化背景概述1.文化起源2.起卦步骤 #二、卦象解读#三、just do i…

力扣116. 填充每个节点的下一个右侧节点指针

Problem: 116. 填充每个节点的下一个右侧节点指针 文章目录 题目描述思路复杂度Code 题目描述 思路 遍历思想(利用二叉树的先序遍历) 本题目的难点在于对于不同父节点的邻接问题因此我们可以抽象将两两节点为一组&#xff08;不同父节点的两个孩子节点也抽象为一组&#xff09…

python学opencv|读取图像(四十九)原理探究:使用cv2.bitwise()系列函数实现图像按位运算

【0】基础定义 按位与运算&#xff1a;两个等长度二进制数上下对齐&#xff0c;全1取1&#xff0c;其余取0。 按位或运算&#xff1a;两个等长度二进制数上下对齐&#xff0c;有1取1&#xff0c;其余取0。 按位异或运算&#xff1a; 两个等长度二进制数上下对齐&#xff0c;相…

【架构面试】一、架构设计认知

涉及分布式锁、中间件、数据库、分布式缓存、系统高可用等多个技术领域&#xff0c;旨在考查候选人的技术深度、架构设计能力与解决实际问题的能力。 1. 以 Redis 是否可以作为分布式锁为例&#xff1a; 用 Redis 实现分布式锁会存在哪些问题&#xff1f; 死锁&#xff1a;如果…

MySQL基本架构SQL语句在数据库框架中的执行流程数据库的三范式

MySQL基本架构图&#xff1a; MySQL主要分为Server层和存储引擎层 Server层&#xff1a; 连接器&#xff1a;连接客户端&#xff0c;获取权限&#xff0c;管理连接 查询缓存&#xff08;可选&#xff09;&#xff1a;在执行查询语句之前会先到查询缓存中查看是否执行过这条语…