当前位置: 首页 > news >正文

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、回顾数组名&#xff1f;3.2、数组指针定义与初始化&#xff08;格式&#xff09;3.3、数组指针的作用 --- 常用于二维数组3.4、数…...

【Go 基础篇】Go 语言字符串函数详解:处理字符串进阶

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

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标签有什么用?

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

docker在阿里云上的镜像仓库管理

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

html-dom核心内容--四要素

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

golang的继承

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

Google Play商店优化排名因素之应用截图与视频

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

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&#xff09;创建文件 创建文件时&#xff0c;文件的路径一定是全英文 2&#xff09;修改编码 工具--->选项--->行为--->默认编码&#xff1a;system 【2】C和C的区别 C又叫C plus plus&#xff0c;C是对C的扩充&…...

Linux上实现分片压缩及解压分片zip压缩包 - 及zip、unzip命令详解

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; &#x1f40b; 希望大家多多支…...

概率论作业啊啊啊

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 计算加权平均数&#xff0c;其中权重为: 2 , 1 , 3 , 2 ,…...

React re-render

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

从零开始配置Jenkins与GitLab集成:一步步实现持续集成

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

高效多用的群集-Haproxy搭建Web集群

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

aws的s3匿名公开访问

点击桶权限 &#xff0c;添加策略 {"Version": "2012-10-17","Statement": [{"Sid": "AddPerm","Effect": "Allow","Principal": "*","Action": "s3:GetObject&qu…...

2023科隆游戏展:虚幻5游戏百花齐放,云渲染助力虚幻5高速渲染

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

Spark大数据分析与实战笔记(第一章 Scala语言基础-2)

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

Linux 下 Mysql 的使用(Ubuntu20.04)

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

牛客练习赛114

A.最后有0得数肯定是10得倍数&#xff0c;然后直接排序即可 #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…...

规范“信息安全”五大举措:江湖背调如何定义背调行业的“金融级”合规标准?

在《个人信息保护法》&#xff08;PIPL&#xff09;与《数据安全法》双重监管下&#xff0c;背景调查早已超出单纯人才信息核实范畴&#xff0c;升级为全流程隐私保卫战。针对AI易抓取结构化数据的行业痛点&#xff0c;江湖背调搭建金融级数据安全防护体系&#xff0c;落地五大…...

Python实现中国象棋AI对战【完整代码+算法解析】

1. 中国象棋AI对战系统设计思路 中国象棋AI对战系统的核心在于将传统规则转化为计算机可执行的逻辑&#xff0c;同时赋予AI"思考"能力。我最初尝试开发这个项目时&#xff0c;发现最大的挑战不是代码实现&#xff0c;而是如何让AI理解象棋的策略本质。经过多次迭代&a…...

UE5开发者必备:10个免费3D模型资源网站推荐(含避坑指南)

UE5开发者必备&#xff1a;10个免费3D模型资源网站深度评测与实战指南 当你深夜盯着UE5编辑器里那个孤零零的默认立方体发呆时&#xff0c;是否也经历过这种绝望&#xff1f;作为经历过上百个原型项目的老司机&#xff0c;我深刻理解优质3D资源对开发效率的致命影响。市面上90…...

ESP32S3上电重启问题终极排查指南:从电源纹波到SPI电阻的实战经验

ESP32S3上电重启问题终极排查指南&#xff1a;从电源纹波到SPI电阻的实战经验 当ESP32S3开发板在批量生产中出现上电重启问题时&#xff0c;硬件工程师往往会面临一场与时间赛跑的挑战。最近在调试某款智能家居网关时&#xff0c;我们遇到了典型的RTC_SW_SYS_RST错误&#xff…...

Meixiong Niannian画图引擎Typora集成:Markdown文档图像生成

Meixiong Niannian画图引擎Typora集成&#xff1a;Markdown文档图像生成 1. 为什么文档作者需要在Typora里直接画图&#xff1f; 你有没有过这样的经历&#xff1a;写技术文档时&#xff0c;突然需要一张示意图来说明某个流程&#xff1b;写产品需求时&#xff0c;想快速画个…...

小说作者必备:次元画室快速构建角色设定,灵感秒变草图

小说作者必备&#xff1a;次元画室快速构建角色设定&#xff0c;灵感秒变草图 你是否经常遇到这样的困境&#xff1a;脑海中浮现出一个鲜活的角色形象&#xff0c;却苦于无法用文字准确描述&#xff1f;或者写好了人物设定&#xff0c;却找不到合适的画师将其可视化&#xff1…...

Qwen-Image-Layered场景实战:用AI图层技术为你的产品图换背景

Qwen-Image-Layered场景实战&#xff1a;用AI图层技术为你的产品图换背景 1. 引言 1.1 电商设计的痛点 在电商运营中&#xff0c;产品主图的质量直接影响转化率。传统换背景流程需要设计师手动抠图、调整边缘、匹配光影&#xff0c;一个产品图往往需要30分钟以上的处理时间。…...

硬件设计避坑指南:为什么你的AD原理图转PCB总会丢失元器件位号?

硬件工程师必看&#xff1a;AD原理图转PCB丢失元器件位号的深度解析与根治方案 每次打开Altium Designer准备将精心设计的原理图导入PCB时&#xff0c;却发现所有元器件位号神秘消失——这种场景对硬件工程师来说简直是一场噩梦。位号不仅是元器件在PCB上的身份标识&#xff0c…...

MySQL存储图片旋转元数据的最佳实践

MySQL存储图片旋转元数据的最佳实践 1. 引言 在日常应用中&#xff0c;我们经常遇到这样的场景&#xff1a;用户上传的图片在显示时方向不正确&#xff0c;需要根据EXIF信息中的旋转角度进行自动校正。比如手机拍摄的照片&#xff0c;由于设备方向不同&#xff0c;可能包含90…...

ZYNQ XADC保姆级教程:不写PL代码,用PS接口3分钟读取芯片温度电压

ZYNQ XADC极简实战&#xff1a;纯PS端3行代码监控芯片健康状况 刚拿到ZYNQ开发板时&#xff0c;我最先好奇的是这颗芯片的"生命体征"——它现在多少度&#xff1f;供电稳定吗&#xff1f;传统FPGA需要外接传感器才能获取这些数据&#xff0c;而ZYNQ内置的XADC模块让这…...