C语言学习笔记---指针进阶01
C语言程序设计笔记---016
- C语言指针进阶前篇
- 1、字符指针
- 2、指针数组
- 2.1、指针数组例程1 -- 模拟一个二维数组
- 2.2、指针数组例程2
- 3、数组指针
- 3.1、回顾数组名?
- 3.2、数组指针定义与初始化(格式)
- 3.3、数组指针的作用 --- 常用于二维数组
- 3.4、数组指针 --- 二维数组的应用
- 4、数组的参数探究 --- 指针参数作为参数
- 4.1、一维数组传参
- 4.2、二维数组传参
- 4.3、指针传参
- 5、函数指针
- 5.1、函数指针初始化(格式)
- 6、巩固知识点
- 6.1、解释以下代码1
- 6.2、解释以下代码2
- 7、结语
C语言指针进阶前篇
前言:
什么是指针?
指针是编程语言中的一个对象,利用地址,它的值直接指向存在电脑存储器中另一个地方的值。
由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”
即:能通过它能找到以它为地址的内存单元
另外,平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量。
/知识点汇总/
1.指针变量就是变量,用来存放地址,地址唯一标识一块内存空间
2.指针的大小,是固定的4/8个字节(32位/64位)、
3.指针是有类型的,指针的类型决定了指针±整数的步长,以及指针解引用的权限、
4.指针的运算(指针加减整数:偏移量;指针减指针:是指针和指针之间的元素个数;指针关系运算:指针大小比较)
详见:指针初阶
1、字符指针
指针就是地址,口语中说的指针指的是指针变量
整型指针:指向整型数据的指针
字符指针:就是指向字符型数据的指针变量
#include <stdio.h>
int main()
{char ch = 'w';char* pc = &ch;char* p = "abcdef";//这里的字符串等价于表达式,然后返回的结果是第一个字符的地址(可理解为数组)//注意的是,这里的“abcdef”属于常量表达式,不可改变printf("%c\n","abcdef"[3]);//d//类似于数组名 --- “abcdef” ,所以可理解为数组形式const* pd = "abccdef";printf("%s\n", pd);//abcdefprintf("%c\n", *pd);//areturn 0;
}
注意的是:
(1)、这里的字符串等价于表达式,然后返回的结果是第一个字符的地址(可理解为数组)
(2)、这里的“abcdef”属于常量表达式,不可改变
例题:
#include <stdio.h>
int main()
{char str1[] = "hello bit.";char str2[] = "hello bit.";const char str3 = "hello bit.";const char str4 = "hello bit.";if (str1 == str2){printf("1 to 2 same\n");}else{printf("1 to 2 not same\n");}if (str3 == str4){printf("3 to 4 same\n");}else{printf("3 to 4 not same\n");}if (&str3 == &str4){printf("&3 to &4 same\n");}else{printf("&3 to &4 not same\n");}return 0;
}
小结:
(1)、str1 与 str2 是两个不同的空间地址所以,不相等
(2)、str3 与 str4 由于保存的是同一个常量表达式,所以它们指向的地址相同,则得到的值相同;但是str3 和str4 本身的地址是不同的
2、指针数组
字符数组 – 存放字符的数组
整型数组 – 存放整型的数组
指针数组 – 存放指针的数组,存放在数组中的元素是指针类型
如:
int* arr[5];
char* ch[6];
2.1、指针数组例程1 – 模拟一个二维数组
#include <stdio.h>
int main()
{int arr1[] = { 1,2,3,4,5 };int arr2[] = { 2,3,4,5,6 };int arr3[] = { 3,4,5,6,7 };//int* int* int*//指针数组int* arr[] = {arr1,arr2,arr3};int i = 0;for (i = 0; i < 3; i++){int j = 0;for (j = 0; j < 5; j++){printf("%d ",arr[i][j]);}printf("\n");}return 0;
}
2.2、指针数组例程2
#include <stdio.h>
int main()
{//指针数组char* arr[5] = {"hello bit","hehe","abcf","cojag","waofrdf"};int i = 0;for (i = 0; i < 5; i++){printf("%s\n",arr[i]);}return 0;
}
3、数组指针
指针数组 ---- 是数组,是存放指针的数组
数组指针 — 是指针
字符指针 — 是指向字符的指针
整型指针 – 指向整型的指针
浮点型指针 – 指向浮点数的指针
3.1、回顾数组名?
数组名是数组首元素的地址,但是存在两个例外,sizeof(数组名),&数组名;
两个例外的数组名,表达的是,整个数组的地址
数组指针 — &arr
虽然与首元素地址值相同,但进行指针运算时±,发现,加减的整个数组的大小字节
同时指针类型决定了,指针+1,到底+几个字节(步长)
#include <stdio.h>
int main()
{int arr[10];printf("%p\n",arr);printf("%p\n",arr+1);printf("%p\n", &arr);printf("%p\n", &arr + 1);printf("%p\n", arr[0]);printf("%p\n", arr[0] + 1);printf("%p\n", &arr[0]);printf("%p\n", &arr[0] + 1);return 0;
}
3.2、数组指针定义与初始化(格式)
#include <stdio.h>
int main()
{int arr[10] = { 0 };//int* p = &arr;int(*p)[10] = &arr;//p是用来存放数组的地址的,p就是数组指针char* arr2[5];char* (*pc)[5] = &arr2;//(*pc)说明pc是一个指针类型,(*pc)[5],表示数组指针,char* 表示该数组类型属于字符指针类型//int arr3[] = { 1,2,3 };//int(*p3)[] = &arr3;//数组指针的[]操作符的参数必须指明,否则报错return 0;
}
3.3、数组指针的作用 — 常用于二维数组
#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };//数组指针int(*p)[10] = &arr;int i = 0;for(i=0;i<10;i++){printf("%d ",(*p)[i]);}//指针变量int* p = &arr;int i = 0;for (i = 0; i < 10; i++){printf("%d ", p[i]);}return 0;
}
3.4、数组指针 — 二维数组的应用
二维数组的数组名是首元素的地址,即:数组指针的首元素地址是,第一行的地址
#include <stdio.h>
//二维数组传参也是二维数组的形式
//void print(int arr[3][5], int row, int col)//形参是数组形式
//{
// int i = 0;
// for (i = 0; i < 3; i++)
// {
// int j = 0;
// for (j = 0; j < 5; j++)
// {
// printf("%d ",arr[i][j]);
// }
// printf("\n");
// }
//}
void print(int (*p)[5], int row, int col)//形参是指针形式,指向第一行
{int i = 0;for (i = 0; i < 3; i++){int j = 0;for (j = 0; j < 5; j++){printf("%d ",p[i][j]);}printf("\n");}
}
int main()
{int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{6,7,8,9,10} };print(arr,3,5);//二维数组传参,行,列return 0;
}
4、数组的参数探究 — 指针参数作为参数
4.1、一维数组传参
#include <stdio.h>void test(int arr[])//ok
{}
void test(int arr[10])//ok
{}
void test(int *arr)//ok
{}
void test2(int* arr[20])//ok
{}
void test2(int* *arr)//ok
{}
int main()
{int arr[10] = { 0 };int* arr2[20] = { 0 };test(arr);test2(arr2);return 0;
}
4.2、二维数组传参
#include <stdio.h>void test(int arr[3][5])//ok
{}
void test(int arr[][])//No,列不可以省
{}
void test(int arr[][5])//ok
{}
void test(int *arr)//No,不能以一维数组接收二维数组,因为二维数组的首元素地址是第一行的地址,而不是第一个元素的地址
{}
void test(int* arr[5])//No,类型不同,int* 与int
{}
void test(int (*arr)[5])//ok,数组指针,指向第一行
{}
void test(int **arr)//No,二级指针用于指向一级指针的地址
{}int main()
{int arr[3][5];test(arr);return 0;
}
4.3、指针传参
一级指针传参:
一级指针传参时,形参写成一级指针形式
#include <stdio.h>
void print(int* p, int sz)//一级指针传参时,形参写成一级指针形式就可以了
{int i = 0;for (i = 0; i < sz; i++){printf("%d\n",*(p+i));}
}
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int* p = arr;int sz = sizeof(arr) / sizeof(arr[0]);//一级指针p传给函数,作形参print(p,sz);return 0;
}
思考扩展1:
当我们遇见一个函数的形参是一级指针的时候,考虑函数的实参可以传什么?
答:只要是可以传递的对应类型的地址/一级指针变量就可以,以及数组名也行。
二级指针传参:
二级指针传参时,形参写成二级指针形式
#include <stdio.h>void test(int** ptr)
{printf("num = %d\n",**ptr);
}int main()
{int n = 10;int* p = &n;int** pp = &p;test(pp);//test(&p);等价return 0;
}
思考扩展2:
当我们遇见一个函数的形参是一级指针的时候,考虑函数的实参可以传什么?
答:只要是可以传递的对应类型的一级指针地址/二级指针变量就可以,一级指针类型的数组名也行。
5、函数指针
数组指针 – 指向数组的指针 – 存放的是数组的地址 — &数组名就是整个数组的地址
函数指针 – 指向函数的指针 — 存放的是函数的地址
如何取得函数的地址呢?也是通过 &函数名吗?
答:&操作符加函数名即可
5.1、函数指针初始化(格式)
#include <stdio.h>int Add(int x, int y)
{return (x + y);
}int main()
{//&函数名就是函数的地址//函数名也是函数的地址printf("%p\n", &Add);printf("%p\n", Add);//均表示函数的地址//函数指针//int (*pf1)(int , int) = Add;//pf1就是函数指针变量int (*pf2)(int, int) = &Add;//pf2同样是函数指针变量int ret = (*pf2)(2, 3);//因为Add与&Add等价//常规写法://int ret = Add(2,3);//所以*号就可以省略//int ret = pf2(2,3)printf("%d\n",ret);
}
6、巩固知识点
6.1、解释以下代码1
int arr[5];//arr是一个存放5个整型数据的数组
int* parr1[10];//parr1是一个数组,数组的10个元素类型是int*
int(*parr2)[10];//parr2是一个数组指针,该指针指向的数组,指向数组的10个元素类型是int
int(*parr3[10])[5];//parr3是一个数组,是存放数组指针的10元素的数组,存放的这个数组指针,指针指向的5个元素是int类型
6.2、解释以下代码2
#include <stdio.h>
int main()
{(*(void(*)())0)();//整体是一个函数调用//(void(*)()函数指针类型//(void(*)()) 强制类型转换为函数指针类型//(*(类型)0)(); --- 所以这段代码表示://调用0地址处的函数,这个函数没有参数,且返回值类型为void省略不写void (*signal(int, void(*)(int)))(int);//整体是一个函数声明//void(*)(int)函数指针作为参数//signal(int, void(*)(int)) --- 函数,一个参数是int类型,一个参数是函数指针类型,返回值类型也是作为函数指针类型//(*signal(int, void(*)(int))) --- 函数指针//(*signal(int, void(*)(int)))(int) --- 函数指针参数是一个int类型参数//void (*signal(int, void(*)(int)))(int) -- 一个返回值类型为空,参数是一个整型的函数指针的声明//所以这段代码表示://是一个函数声明,声明的是signal函数,signal函数的参数有两个,一个是int类型,一个是函数指针类型,该类型是void(*)(int),该函数指针指向的函数,参数类型是int类型,返回值类型为void//signal函数的返回值类型也是函数指针类型,该类型是void (*)(int),该函数指针指向的函数,参数类型是int类型,返回值类型为void//利用typedef 对这段代码简化:typedef void(*pfun_t)(int);//typedef 对函数指针类型重命名时,被重名的变量名,放在*面,即pfun_t的位置pfun_t signal(int, pfun_t);return 0;
}
7、结语
C语言指针进阶前篇到此结束啦!
未完待续…
半亩方糖一鉴开,天光云影共徘徊。
问渠哪得清如许?为有源头活水来。–朱熹(观书有感)
相关文章:

C语言学习笔记---指针进阶01
C语言程序设计笔记---016 C语言指针进阶前篇1、字符指针2、指针数组2.1、指针数组例程1 -- 模拟一个二维数组2.2、指针数组例程2 3、数组指针3.1、回顾数组名?3.2、数组指针定义与初始化(格式)3.3、数组指针的作用 --- 常用于二维数组3.4、数…...

【Go 基础篇】Go 语言字符串函数详解:处理字符串进阶
大家好!继续我们关于Go语言中字符串函数的探索。字符串是编程中常用的数据类型,而Go语言为我们提供了一系列实用的字符串函数,方便我们进行各种操作,如查找、截取、替换等。在上一篇博客的基础上,我们将继续介绍更多字…...

GAN原理 代码解读
模型架构 代码 数据准备 import os import time import matplotlib.pyplot as plt import numpy as np import torchvision.transforms as transforms from torch.utils.data import DataLoader from torchvision import datasets import torch.nn as nn import torch# 创建文…...

HTML的label标签有什么用?
当你想要将表单元素(如输入框、复选框、单选按钮等)与其描述文本关联起来,以便提供更好的用户界面和可访问性时,就可以使用HTML中的<label>标签。<label>标签用于为表单元素提供标签或标识,使用户能够更清…...

docker在阿里云上的镜像仓库管理
目录 一.登录进入阿里云网站,点击个人实例进行创建 二.创建仓库,填写相关信息 三.在访问凭证中设置固定密码用于登录,登录时用户名是使用你注册阿里云的账号名称,密码使用设置的固定密码 四.为镜像打标签并推送到仓库 五.拉取…...

html-dom核心内容--四要素
1、结构 HTML DOM (文档对象模型) 当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model)。 2、核心关注的内容:“元素”,“属性”,“修改样式”,“事件反应”。>四要素…...

golang的继承
golang中并没有继承以及oop,但是我们可以通过struct嵌套来完成这个操作。 定义struct 以下定义了一个Person结构体,这个结构体有Eat方法以及三个属性 type Person struct {Name stringAge uint16Phone string }func (recv *Person) Eat() {fmt.Prin…...

Google Play商店优化排名因素之应用截图与视频
屏幕截图是影响转化率的最重要的视觉效果之一。大多数人只需查看应用程序屏幕截图,就会决定是否尝试去下载我们的应用程序。 1、在Google Play商店中,搜索结果页面根据我们搜索的关键词有不同的样式。 展示应用程序中最好的部分,添加一些文字…...

fastadmin iis伪静态应用入口文件index.php
<?xml version"1.0" encoding"UTF-8"?> <configuration><system.webServer><rewrite><rules><rule name"OrgPage" stopProcessing"true"><match url"^(.*)$" /><conditions…...

0821|C++day1 初步认识C++
一、思维导图 二、知识点回顾 【1】QT软件的使用 1)创建文件 创建文件时,文件的路径一定是全英文 2)修改编码 工具--->选项--->行为--->默认编码:system 【2】C和C的区别 C又叫C plus plus,C是对C的扩充&…...

Linux上实现分片压缩及解压分片zip压缩包 - 及zip、unzip命令详解
👨🎓博主简介 🏅云计算领域优质创作者 🏅华为云开发者社区专家博主 🏅阿里云开发者社区专家博主 💊交流社区:运维交流社区 欢迎大家的加入! 🐋 希望大家多多支…...

概率论作业啊啊啊
1 数据位置 (Measures of location) 对于数据集: 7 , 9 , 9 , 10 , 10 , 11 , 11 , 12 , 12 , 12 , 13 , 14 , 14 , 15 , 16 7,9,9,10,10,11,11,12,12,12,13,14,14,15,16 7,9,9,10,10,11,11,12,12,12,13,14,14,15,16 计算加权平均数,其中权重为: 2 , 1 , 3 , 2 ,…...

React re-render
What is? react的渲染分为两个阶段: render,组件第一次出现在屏幕上的时候触发re-render, 组件第一次渲染之后的渲染 当app的数据更新时(用户手动更新、或异步请求)。 When? re-render发生有四种可能: state改变…...

从零开始配置Jenkins与GitLab集成:一步步实现持续集成
在软件开发中,持续集成是确保高效协作和可靠交付的核心实践。以下是在CentOS上安装配置Jenkins与GitLab集成的详细步骤: 1.安装JDK 解压JDK安装包并设置环境变量: JDK下载网址 Java Downloads | Oracle 台灣 tar zxvf jdk-11.0.5_linux-x64_b…...

高效多用的群集-Haproxy搭建Web集群
Haproxy搭建 Web 群集 一、Haproxy前言 HAProxy是一个使用c语言编写的自由及开放源代码软件,其提供高可用性、负载均衡,以及基于TcP和HrrP的应用程序代理。HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。…...

aws的s3匿名公开访问
点击桶权限 ,添加策略 {"Version": "2012-10-17","Statement": [{"Sid": "AddPerm","Effect": "Allow","Principal": "*","Action": "s3:GetObject&qu…...

2023科隆游戏展:虚幻5游戏百花齐放,云渲染助力虚幻5高速渲染
8月23日,欧洲权威级游戏展示会——科隆游戏展拉开帷幕。今年的参展游戏也相当给力,数十款游戏新预告片在展会上公布,其中有不少游戏使用虚幻5引擎制作,开创了游戏开发新纪元。 虚幻5游戏百花齐放,渲染堪比电影级效果 …...

Spark大数据分析与实战笔记(第一章 Scala语言基础-2)
文章目录 章节概要1.2 Scala的基础语法1.2.1 声明值和变量1.2.2 数据类型1.2.3 算术和操作符重载1.2.4 控制结构语句1.2.5 方法和函数 章节概要 Spark是专为大规模数据处理而设计的快速通用的计算引擎,它是由Scala语言开发实现的,关于大数据技术…...

Linux 下 Mysql 的使用(Ubuntu20.04)
文章目录 一、安装二、使用2.1 登录2.2 数据库操作2.2.1 创建数据库2.2.2 删除数据库2.2.3 创建数据表 参考文档 一、安装 Linux 下 Mysql 的安装非常简单,一个命令即可: sudo apt install mysql-server检查安装是否成功,输入: …...

牛客练习赛114
A.最后有0得数肯定是10得倍数,然后直接排序即可 #include<bits/stdc.h> using namespace std; const int N 1e610,mod1e97; int n; void solve(){cin>>n;vector<int> a(n);for(auto&i:a) cin>>i;sort(a.begin(),a.end(),greater<&g…...

Http与Https
1.简单介绍 HTTP:最广泛应用的网络通信协议,基于TCP,数据传输简单高效,数据是明文。 HTTPS:是HTTP的加强版,是HTTPSSL。在HTTP的基础上加了安全机制,一方面保证数据的安全传输,另一…...

前端通信(渲染、http、缓存、异步、跨域)自用笔记
SSR/CSR:HTML拼接?网页源码?SEO/交互性 SSR (server side render)服务端渲染,是指由服务侧(server side)完成页面的DOM结构拼接,然后发送到浏览器,为其绑定状…...

43.227.198.x怎么检查服务器里是否中毒情况?
要检查43.227.198.1服务器是否中毒,可以执行以下步骤: 运行杀毒软件:运行已安装的杀毒软件进行全盘扫描,查看是否有病毒或恶意软件。如果发现病毒或恶意软件,立即将其删除或隔离。 检查系统文件:检查服务器…...

Sentinel dashboard无法查询到应用的限流配置问题以及解决
一。问题引入 使用sentinle-dashboard控制台 项目整体升级后,发现控制台上无法看到流控规则了 之前的问题是无法注册上来 现在是注册上来了。结果看不到流控规则配置了。 关于注册不上来的问题,可以看另一篇文章 https://blog.csdn.net/a15835774652/…...

【Spring Boot】社交网站中验证用户登录的checkUser方法
public boolean checkUser(User user) {User userInDb userRepository.findByUsername(user.getUsername());if (userInDb ! null && userInDb.getPassword().equals(user.getPassword())) {return true;} else {return false;}} } 这段代码是UserService类中的checkU…...

edge浏览器进行qq截图过保爆决过程
edge浏览器进行qq截图过保解决过程 参考:电脑截屏曝光特别高怎么解决? - 知乎 问题展示 饱和度过高,刺眼 1. 在chrome地址栏输入chrome://flags/ 2. 在页面的搜索栏搜索force color profile 3. 在选项中选择所对应的颜色管理。(…...

【Linux】Linux在防火墙firewall中开放或删除某端口
在生产中往往是不能关闭防火墙firewall的(以下操作是在linux中执行的) #补充一下查看防火墙的命令 #查看防火墙状态 systemctl status firewalld #关闭防火墙 systemctl stop firewalld #重启防火墙 systemctl restart firewalld #启动防火墙 systemctl …...

C++构造函数初始化列表
构造函数的一项重要功能是对成员变量进行初始化,为了达到这个目的,可以在构造函数的函数体中对成员变量一一赋值,还可以采用初始化列表。 C构造函数的初始化列表使得代码更加简洁,请看下面的例子: #include <iostre…...

c语言调用mciSendString播放音乐
如下所示,这是一个使用c语言调用系统方法mciSendString(),让系统播放音乐的示例: baihuaxiang 代码: #include <graphics.h> #include <Windows.h> #include <mmsystem.h>#pragma comment(lib,"WINMM.LIB…...

Qt:qRegisterMetaType为Qt信号和槽添加自定义参数类型
背景 qt信号和槽之间的参数传递默认只能传递qt内部已有的类型,例如QString等,若我们自定义类型作为参数时,虽然编译不会报错,但运行时会提示connect无效,无法识别自定义的类。 此时需要我们将自定义类进行注册&#…...