C语言实验4:指针
目录
一、实验要求
二、实验原理
1. 指针的基本概念
1.1 指针的定义
1.2 取地址运算符(&)
1.3 间接引用运算符(*)
2. 指针的基本操作
2.1 指针的赋值
2.2 空指针
3. 指针和数组
3.1 数组和指针的关系
3.2 指针和数组的结合
4. 指针和函数
4.1 指针作为函数参数
5. 动态内存分配
5.1 malloc 和 free 函数
三、实验内容
3.1
代码
截图
分析
3.2
代码
截图
分析
一、实验要求
- 掌握指针和间接访问的概念,会定义和使用指针变量。
- 能正确使用数组的指针和指向数组的指针变量。
- 能正确使用字符串的指针和指向字符串的指针变量。
二、实验原理
指针是C语言中非常重要且强大的概念之一。它提供了直接访问内存地址的能力,使得程序可以更加灵活地处理数据。
1. 指针的基本概念
1.1 指针的定义
指针是一个变量,其值是另一个变量的地址。通过指针,可以直接访问存储在该地址上的数据。
int *ptr; // 定义一个指向整数的指针
1.2 取地址运算符(&)
用于获取变量的地址。
int num = 10;
int *ptr = # // ptr指向num的地址
例如
#include<iostream>
using namespace std;
int main() {int a=10,*ptr;ptr = &a;cout << a <<" "<<ptr;return 0;
}
它的结果是

表面a的地址为000000ECA8AFF794,共16*4=64位二进制
那么下面的代码为什么地址不相邻呢?
#include<iostream>
using namespace std;
int main() {int a=10,b=11,*ptr,*ptr1;ptr = &a;ptr1 = &b;cout << a <<" "<<ptr<<endl;cout << b << " " << ptr1;return 0;
}

在C语言中,连续定义的两个变量的地址是否相邻,与多个因素有关,其中包括编译器、优化选项、操作系统的内存分配策略等。
对齐(Alignment): 许多体系结构要求数据按照某种规定的边界对齐,以提高访问速度。因此,编译器可能会在变量之间插入填充字节,以确保数据按照正确的边界对齐。这导致即使两个变量类型相同,它们的地址也可能不相邻。
优化: 编译器可能会对代码进行优化,包括对变量的存储和访问进行优化。这可能导致变量的地址不是按照它们在代码中的声明顺序来分配的。
内存分配策略: 操作系统对于内存的分配策略也可能影响变量的地址分布。例如,在某些情况下,操作系统可能会使用随机化技术来增加系统的安全性,这会导致变量的地址不再是连续的。
数据类型: 如果定义的变量类型不同,它们的大小可能也不同,这会影响它们在内存中的布局。
1.3 间接引用运算符(*)
用于访问指针所指向地址上的值。
int value = *ptr; // value等于num的值,通过ptr间接引用
例如
#include<iostream>
using namespace std;
int main() {int a=10,*ptr,value;ptr = &a;value = *ptr;cout << a <<" "<<ptr<<" " <<value<< endl;return 0;
}
结果为

即指针ptr为地址,*ptr代表一个数,&a代表a的地址,&a和ptr可以交换值,属于同一类型
*ptr代表数,a代表数,两者可以交换值,属于同一类型
2. 指针的基本操作
2.1 指针的赋值
可以将一个指针指向另一个变量的地址。
int num1 = 10;
int num2 = 20;
int *ptr = &num1; // ptr指向num1的地址
ptr = &num2; // ptr现在指向num2的地址
例如
#include<iostream>
using namespace std;
int main() {int num1 = 10, num2 = 20;int* ptr = &num1;cout << *ptr <<" "<<ptr<< endl;ptr = &num2;cout << *ptr << " " << ptr;return 0;
}
结果为

2.2 空指针
指向地址为0的指针被称为空指针。
int *ptr = NULL; // ptr是一个空指针
可以猜测一下下述代码的输出结果是什么
#include<iostream>
using namespace std;
int main() {int* ptr = NULL;cout << *ptr <<" "<<ptr<< endl;return 0;
}
答案是!

那空指针有什么作用呢?
1.标记未初始化的指针: 在定义指针变量但尚未为其分配有效内存地址之前,可以将指针初始化为
NULL,表示它当前不指向任何有效的内存区域。2.避免野指针: 将指针初始化为
NULL可以避免使用未初始化的指针(野指针),从而减少程序中出现的错误。3.指针作为空指针常量: 用
NULL表示空指针常量,提高代码的可读性。在函数参数或返回值中,空指针常常用于表示某个指针不指向有效的内存。void process_data(int *data) {if (data != NULL) {// 处理有效的数据} else {// 处理空指针情况} }4.动态内存分配失败的标志: 在动态内存分配时,如果分配失败,
malloc或calloc通常会返回NULL,这可用于检测内存分配是否成功。int *dynamicPtr = (int*)malloc(sizeof(int)); if (dynamicPtr == NULL) {// 内存分配失败// 处理错误的代码 }5.函数返回空指针: 有时,函数可能返回一个空指针作为错误或特殊情况的标志。
int *find_element(int key) {// 查找元素...if (element_not_found) {return NULL;}// 找到元素,返回指向元素的指针 }
3. 指针和数组
3.1 数组和指针的关系
数组名本身就是一个指针,指向数组的第一个元素的地址。
int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr; // ptr指向arr的第一个元素
记住是arr为地址,不是&arr!
3.2 指针和数组的结合
通过指针可以遍历数组的元素。
for (int i = 0; i < 5; ++i) {printf("%d ", *(ptr + i)); // 打印数组元素的值
}
例如
#include<iostream>
using namespace std;
int main() {int* ptr;int a[5] = { 1,2,3,4,5 };ptr = a;for (int i = 0; i < 5; i++) {cout << "第" << i << "个元素为" << *(a + i) << "其地址为"<<a+i<<endl;}return 0;
}
结果为

4. 指针和函数
4.1 指针作为函数参数
可以通过指针在函数间传递数据。
void modifyValue(int *ptr) {*ptr = 100;
}int main() {int num = 10;modifyValue(&num);// 现在num的值变成了100return 0;
}
但是如果不用指针呢?
#include<iostream>
using namespace std;
void modifyValue(int ptr) {ptr = 100;
}
int main() {int num = 10;modifyValue(num);cout << num;return 0;
}
结果是10,所以指针的作用就体现出来了
在这段代码中,问题出现在modifyValue函数的参数类型和传递方式上。在C中,函数参数可以通过值传递或引用传递。在这里,modifyValue函数使用的是值传递,这意味着函数接收到的是实参的一个副本而不是实参本身。
当你调用modifyValue(num)时,将num的值(10)传递给modifyValue函数的形参ptr。在函数内部,ptr被修改为100,但这仅仅是对形参的修改,不会影响实参 num 的值。
所以,当你在main函数中输出num的值时,输出的是原始的值,即10,而不是在modifyValue函数内修改后的值100。
4.2 指针作为函数返回值
函数可以返回指针,使得函数能够返回动态分配的内存。
int* createArray(int size) {int *arr = (int*)malloc(size * sizeof(int));// 初始化数组...return arr;
}
例如
#include<iostream>
using namespace std;
int* createArray(int size) {int* arr = (int*)malloc(size * sizeof(int));return arr;
}int main() {int* ptr;ptr = createArray(5);cout << ptr<<" "<<* ptr;return 0;
}
结果为

为什么*ptr即数组的第一个值那么奇怪呢?
是因为数组只是分配了空间,并没有赋值
5. 动态内存分配
5.1 malloc 和 free 函数
用于动态分配和释放内存。
int *ptr = (int*)malloc(sizeof(int)); // 分配一个整数大小的内存
// 使用ptr...
free(ptr); // 释放内存
sizeof 是一个在 C 和 C++ 等编程语言中常用的操作符,用于获取数据类型或变量在内存中所占用的字节数。sizeof 的语法如下
sizeof(type)
sizeof(expression)
其中,type 是数据类型,而 expression 则是一个表达式或变量。sizeof 返回一个 size_t 类型的值,表示参数所占用的字节数。常用于分配内存。
malloc 是 C 语言中的一个函数,用于动态分配内存。它的名字来源于 "memory allocation"(内存分配)。malloc 函数接受一个参数 size,表示要分配的内存字节数。它返回一个 void 指针,指向分配的内存的起始地址。可以将其转换为适当的类型,以便进行正确的使用。
上述转化为int型指针
free 函数用于释放通过动态内存分配函数(如 malloc、calloc、realloc 等)分配的内存空间。free 函数接受一个指针 ptr,该指针应该是通过动态内存分配函数分配的内存的起始地址。调用 free 函数会将相应的内存空间标记为可用,以便后续的内存分配操作可以使用该空间。
三、实验内容
3.1
将n个数按输入时的顺序逆序排列,用函数实现。
代码
#include<iostream>
using namespace std;
void sort(int* p, int* q, int n) {for (int i = 0; i < n; i++) {*(q + i) = *(p + n - 1 - i);//将q指针所代表的数组的第n-i个元素赋值给p指针所代表的数组的第i+1个元素}
}
int main() {int a[100],b[100],n,*ptr1,*ptr2;ptr1 = a;ptr2 = b;cout << "请输入所需要输入的元素数目:";cin >> n;for (int i = 0; i < n; i++) {cin >> *(ptr1 + i);}sort(ptr1, ptr2, n);for (int i = 0; i < n; i++) {cout << *(ptr2 + i)<<" ";}return 0;
}
截图

分析
void sort(int* p, int* q, int n):这是一个排序函数,接受两个指向整数数组的指针p和q,以及数组的大小n。该函数通过将数组p中的元素逆序复制到数组q中来实现排序。
int main():主函数包含以下步骤:
- 定义两个数组
a和b,以及两个指向整数的指针ptr1和ptr2。- 用户输入所需输入的元素数目
n。- 通过指针
ptr1输入数组a的元素。- 调用
sort函数,将数组a中的元素逆序复制到数组b中。- 输出数组
b中的元素,即排序后的结果。在
sort函数中,通过循环遍历数组,将数组p中的元素逆序复制到数组q中。这通过使用指针算术实现,*(q + i) = *(p + n - 1 - i)将数组p中的第n-i个元素赋值给数组q中的第i+1个元素。
3.2
将一个5×5的矩阵(二维数组)中最大的元素放在中心,4个角分别放4个最小的元素(顺序为从左到右,从上到下依次从小到大存放),写一函数实现。用main函数调用。
代码
#include<iostream>
using namespace std;
int min_max = -9999, index = 0, b[4] = { 0,4,20,24 };//b数组为快速索引,index为min数组中最大元素的序列号int find_min_max(int* ptr) {//找出四个元素中的最大值min_max = -9999;for (int i = 0; i < 4; i++) {if (*(ptr + i) >= min_max) {min_max = *(ptr + i);index = i;}}return min_max;
}
int compare(const void* a, const void* b) {// 比较函数,用于指定排序规则// 返回负数表示 a < b// 返回零表示 a == b// 返回正数表示 a > breturn (*(int*)a - *(int*)b);
}void change(int *ptr) {//找到最大元素和最小的四个元素int max = -9999;int min[4] = { 9999,9999,9999,9999 };int* ptr2=min;//找最大元素和最小的四个元素for (int i = 0; i < 25; i++) {if (*(ptr + i) > max) {max = *(ptr + i);}min_max = find_min_max(ptr2);if (*(ptr + i) < min_max) {//满足进入四个最小元素的数组*(ptr2 + index) = *(ptr + i);//替换位置}}//对四个最小元素的位置进行排序qsort(ptr2, 4, sizeof(int), compare);//更换位置for (int i = 0; i < 25; i++) {if (*(ptr + i) == max) {//如果是最大元素int temp = *(ptr + 12);*(ptr + 12) = max;*(ptr + i) = temp;continue;}}for (int i = 0; i < 25; i++) {for (int j = 0; j < 4; j++) {//如果是较小元素if (*(ptr + i) == min[j]) {int temp = *(ptr + b[j]);cout << "temp " << temp << endl;*(ptr + b[j]) = min[j];*(ptr + i) = temp;continue;} }}
}
int main() {int a[5][5],* ptr1;ptr1 = a[0];for (int i = 0; i < 5; i++) {for (int j = 0; j < 5; j++) {cin >> a[i][j];}}change(ptr1);for (int i = 0; i < 5; i++) {for (int j = 0; j < 5; j++) {cout<< a[i][j]<<" ";}cout << endl;}return 0;
}
截图
![]()

分析
变量定义和初始化:
int min_max = -9999, index = 0, b[4] = { 0,4,20,24 };:定义了全局变量,其中min_max用于存储四个元素中的最大值,index用于存储min数组中最大元素的序列号,b数组是用于快速索引的数组。
find_min_max函数:
- 该函数用于找出四个元素中的最大值,并返回这个最大值。它还会更新
index变量,以表示最大值在min数组中的位置。
compare函数:
- 这是一个比较函数,用于在后续的
qsort函数中进行数组排序。
change函数:
- 该函数对数组进行操作,找到数组中的最大元素和最小的四个元素,然后将它们的位置进行调整。
- 具体操作:
- 找到数组中的最大元素
max。- 找到数组中最小的四个元素,用
min数组保存,并通过调用find_min_max函数找到最小元素中的最大值及其位置。- 使用
qsort对min数组进行排序。- 将最大元素和最小元素的位置进行交换。
- 输出结果。
main函数:
- 定义了一个5x5的数组
a和一个指向该数组的指针ptr1。- 通过用户输入给数组
a赋值。- 调用
change函数对数组进行操作。- 输出最终的数组。
指针是C语言中非常强大和灵活的特性,但也需要小心使用,因为错误的指针操作可能导致程序崩溃或产生不可预测的结果。
指针需慎用!
相关文章:
C语言实验4:指针
目录 一、实验要求 二、实验原理 1. 指针的基本概念 1.1 指针的定义 1.2 取地址运算符(&) 1.3 间接引用运算符(*) 2. 指针的基本操作 2.1 指针的赋值 2.2 空指针 3. 指针和数组 3.1 数组和指针的关系 3.2 指针和数…...
项目——————————
C/C Linux Socket网络编程 TCP 与 UDP_c 语言tcp socket cleint read-CSDN博客C/C Socket - TCP 与 UDP 网络编程_c socket udp-CSDN博客 登录—专业IT笔试面试备考平台_牛客网...
【论文阅读】Realtime multi-person 2d pose estimation using part affinity fields
OpenPose:使用PAF的实时多人2D姿势估计。 code:GitHub - ZheC/Realtime_Multi-Person_Pose_Estimation: Code repo for realtime multi-person pose estimation in CVPR17 (Oral) paper:[1611.08050] Realtime Multi-Person 2D Pose Estima…...
图像分割实战-系列教程9:U2NET显著性检测实战1
🍁🍁🍁图像分割实战-系列教程 总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Pycharm中进行 本篇文章配套的代码资源已经上传 U2NET显著性检测实战1 1、任务概述...
RK3568平台 Android13 GKI架构开发方式
一.GKI简介 GKI:Generic Kernel Image 通用内核映像。 Android13 GMS和EDLA认证的一个难点是google强制要求要支持GKI。GKI通用内核映像,是google为了解决内核碎片化的问题,而设计的通过提供统一核心内核并将SoC和板级驱动从核心内核移至可加…...
阿里云服务器节省计划价格便宜_成本优化全解析
阿里云服务器付费模式节省计划怎么收费?为什么说节省计划更节省成本?节省计划是一种折扣权益计划,可以抵扣按量付费实例(不含抢占式实例)的账单。相比包年包月实例,以及预留实例券和按量付费实例的组合&…...
3种依赖管理工具实现requirements.txt文件生成
1.pip 实现方式 要使用 pip 生成 requirements.txt 文件,可以使用以下命令: pip freeze > requirements.txt这个命令会将当前环境中所有已安装的 Python 包及其版本信息输出到 requirements.txt 文件中。这个文件可以用于共享项目的依赖信息…...
超图iClient3DforCesium地形、影像、模型、在线影像交互示例
超图iClient3DforCesium地形、影像、模型、在线影像交互示例 描述示例代码 描述 数据源:基于iserver发布的三维场景(地形、影像、BIM模型) 在线arcgis影像 应用:目录树展示源数据列表、目录树控制源数据可视化结果显隐、BIM模型点选查询关联属性 示例代…...
【解决】电脑上的WIFI图标不见了咋整?
相信不少同学都遇到过这种情况:电脑上的wifi图标莫名不见了,甚至有时候还是在使用的中途突然断网消失的。 遇到这种情况一般有两种解决方案: 1. 在开机状态下长按电源键30秒以上 这种办法应该是给主板放电,一般应用在wifi6上面。…...
2 - 表结构 | MySQL键值
表结构 | MySQL键值 表管理1. 库的操作2. 表的操作表的创建与删除表的修改复制表 3. 管理表记录 数据类型数值类型字符类型(汉字或者英文字母)日期时间类型 表头存储与日期时间格式的数据枚举类型 数据批量处理 表管理 客户端把数据存储到数据库服务器上…...
Redis(Linux版本7.2.3)
1、停止Redis服务器 [roottssvr1-c1 sysconfig]# ps -ef | grep redis root 322 1 0 10月30 ? 02:58:53 ./bin/redis-server 0.0.0.0:6379 root 32664 12498 0 14:45 pts/0 00:00:00 grep --colorauto redis [roottssvr1-c1 sysconfig]# [roottssvr…...
八股文打卡day18——操作系统(1)
面试题:进程和线程的区别? 我的回答: 1.概念上。进程是系统进行资源分配和调度的基本单位。线程是系统进行运算调度的最小单位。线程是进程的子任务,一个进程至少包含一个线程,一个进程可以运行多个线程,…...
设计模式—行为型模式之模板方法模式
设计模式—行为型模式之模板方法模式 在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。 模板方法(Template Metho…...
机器学习的分类与经典算法
机器学习算法按照学习方式分类,可以分为有监督学习(Supervised Learning)、无监督学习(Unsupervised Learning)、半监督学习(Semi-supervised Learning)、强化学习(Reinforcement Le…...
2.3物理层下面的传输媒体
目录 2.3物理层下面的传输媒体2.3.1导引型传输媒体1.双绞线2.同轴电缆3.光纤 2.3.2非导引型传输媒体无线电微波通信 2.3物理层下面的传输媒体 传输媒体是数据传输系统中在发送器和接收器之间的物理通路 两大类: 导引型传输媒体:电磁波被导引沿着固体媒体…...
笙默考试管理系统-MyExamTest----codemirror(57)
笙默考试管理系统-MyExamTest----codemirror(57) 目录 一、 笙默考试管理系统-MyExamTest----codemirror 二、 笙默考试管理系统-MyExamTest----codemirror 三、 笙默考试管理系统-MyExamTest----codemirror 四、 笙默考试管理系统-MyExamTest---…...
Qt高质量的开源项目合集
文章目录 1.Qt官网下载/文档2.第三方开源 1.Qt官网下载/文档 Qt Downloads Qt 清华大学开源软件镜像站 Qt 官方博客 2.第三方开源 记录了平常项目开发中用到的第三方库,以及一些值得参考的项目! Qt AV 基于Qt和FFmpeg的跨平台高性能音视频播放框…...
HarmonyOS ARKUI深度解析:图像组件及权限配置实战指南
文章目录 深入学习RKUI中的图片组件及权限配置图片组件简介图片源的三种格式Image : 图片显示组件图片组件属性及样式控制图片权限配置文章总结问题总结深入学习RKUI中的图片组件及权限配置 在本文中,我们将深入学习ArkUI(HarmonyOS UI框架)中的图片组件及其相关属性,同时…...
萨姆·奥尔特曼的预言
Sam Altman(萨姆奥尔特曼)是 OpenAI 的首席执行官,这家初创公司开发了众所周知的 ChatGPT。2023年11月,他突然被董事会解雇,并短暂调往微软。在 OpenAI 的每个人都威胁要辞职后,他又回来了。 新的商业模式…...
iPhone 13 Pro 更换『移植电芯』和『超容电池』体验
文章目录 考虑换电池Ⅰ 方案一Ⅱ 方案二 总结危险 Note系列地址 简 述: 首发买的iPhone 13P (2021.09),随性使用一年出头,容量就暴跌 85%,对比朋友一起买的同款,还是95%。这已经基本得一天两充 >_<&a…...
【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
Golang——9、反射和文件操作
反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...
R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...
【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...
Qt 事件处理中 return 的深入解析
Qt 事件处理中 return 的深入解析 在 Qt 事件处理中,return 语句的使用是另一个关键概念,它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别:不同层级的事件处理 方…...
