『C语言进阶』指针进阶(一)

在这里插入图片描述
🔥博客主页 小羊失眠啦
🔖系列专栏 C语言
🌥️每日语录无论你怎么选,都难免会有遗憾。
❤️感谢大家点赞👍收藏⭐评论✍️


在这里插入图片描述

前言

在C语言初阶中,我们对指针有了一定的了解,指针是个变量,是用来存放地址的,指针的大小是固定的4/8个字节,指针是有类型的,指针的类型决定了指针的±整数的步长以及指针的运算,小羊最近已经开学,博客可以正常更新了,好啦,接下来让我们再进一步的了解指针!!


一、字符指针

我们可以定义一个字符指针,指向一个字符变量,并通过指针来修改这个字符变量

例1

#include<stdio.h>
int main()
{char ch = 'x';char* p = &ch;//pc是字符指针ch = 'a';*p = 'a';return 0;
}
//ch是字符变量,可以直接改变ch的值,
//pc这时是字符指针,存放的是ch的地址,也可以通过指针来改变变量ch的值。

例2

#include<stdio.h>
int main()
{char arr[] = "abcdefg";//创建数组,用字符串来初始化char* p = "abcdefg";//常量字符串,"abcdefg"存放在"常量区",只读,不允许被修改//指针变量p存放的是字符串首元素的地址*p='a';//erro 这种情况会报错,pa不能改变为w
}

例3:这段代码运行结果是什么?

int main()
{char* s = "abcdefg";for (int i = 0; i < 4; i++){*(s + i) = '0';}printf("%s\n", s);return 0;
}

结果:

运行错误,原因是"abcdefg"是常量字符串,它们存放在"常量区",只读,不允许被修改,所以一般写成const char* s="abcdefg"

笔试题

int main()
{char str1[] = "hello bit.";char str2[] = "hello bit.";const char* str3 = "hello bit.";const char* str4 = "hello bit.";if (str1 == str2)printf("str1 and str2 are same\n");elseprintf("str1 and str2 are not same\n");if (str3 == str4)printf("str3 and str4 are same\n");elseprintf("str3 and str4 are not same\n");return 0;
}

在这里插入图片描述

结果分析:

str1和str2是两个字符数组,两个数组是相互独立的,在创建时,会各自向空间申请空间,所以地址是不一样的,只是内存中两块不同内存区域存放着相同内容而已,故str1!=str2
str3和str4里面存放的地址是同一个,都是h的地址,所以是一样的


二、指针数组

2.1 认识指针数组

在C语言初阶里的初识指针中,铁汁们对指针数组也有一定的了解,指针数组是一个存放指针的数组。

整形数组--存放整形的数组
字符数组--存放字符的数组
指针数组--存放指针的数组

#include<stdio.h>
int main()
{int arr1[3];  //存放了三个整形的数组 int int intint* arr2[3]; //存放了三个整形指针的数组 int* int* int*char* arr3[3];//存放了三个一级字符指针的数组 char* char* char*char** arr4[3];//存放了三个二级字符指针的数组 char** char** char**return 0;
}

牛刀小试

int main()
{char* arr[] = { "abcd","efgh","igkl" };int sz = sizeof(arr) / sizeof(arr[0]);for (int i = 0; i < sz; i++)printf("%s ", arr[i]);return 0;
}

在这里插入图片描述

arr是首元素地址

2.2 使用指针数组模拟二维数组

#include<stdio.h>
int main()
{int arr1[4] = { 1,2,3,4 };int arr2[4] = { 2,3,4,5 };int arr3[4] = { 3,4,5,6 };int arr4[4] = { 4,5,6,7 };int* arr[4] = { arr1,arr2,arr3,arr4 };int sz = sizeof(arr) / sizeof(arr[0]);for (int i = 0; i < sz; i++){for (int j = 0; j < 4; j++){printf("%d ", *(arr[i] + j));}printf("\n");}return 0;
}

在这里插入图片描述
结果分析:

经过调试内存可得:int arr1[4] = { 1,2,3,4 };              //arr1的地址是:0x0000001C526FF7F8int arr2[4] = { 2,3,4,5 };              //arr2的地址是:0x0000001C526FF828int arr3[4] = { 3,4,5,6 };              //arr3的地址是:0x0000001C526FF858int arr4[4] = { 4,5,6,7 };              //arr4的地址是:0x0000001C526FF888
由此可见,arr1,arr2,arr3,arr4数组内存中有独立的内存空间,并不是连续的四个内存空间,
我们将这四个一维数组的首元素的地址放在指针数组arr中,通过指针数组来访问这四个一维数组,效果和二维数组是一样的,但是并不是真正的二维数组!!

三、数组指针

3.1 数组指针的定义

定义:指向数组指针被称为数组指针
由于指针数组和数组指针对于初学者很容易混肴,所以我们先通过类比的方法来认识数组指针。

字符指针–指向字符变量的指针,即存放字符变量地址的指针变量。
整型指针–指向整型变量的指针。即存放整型变量地址的指针变量
数组指针–指向数组变量的指针。即存放数组变量地址的指针变量

#include<stdio.h>
int main()
{int a = 2;int* p = &a; int arr[10]; int* arr[10];  //arr先和[10]结合,所以arr是一个数组,里面存的都是指针变量,即为指针数组int(*arr)[10];//arr先和*结合所以arr是一个指针变量,又指向数组,即为指针数组return 0;
}

解释:p先和*结合,说明p是一个指针变量,然后指向一个大小为10个整型的数组(指向的类型 int [10])。所以p是一个指针,指向一个数组,叫数组指针。

注意:[ ]的优先级要高于*号的,所以必须加上()来保证p先和*结合。

3.2 &数组名VS数组名

  • 通常情况下,数组名是首元素地址
  • sizeof(数组名):计算的是整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数组
  • &数组名:取出的是数组的地址,&数组名,数组名表示整个数组
#include<stdio.h>
int main()
{int arr[5] = { 0,1,2,3,4 };printf("  arr=%p\n", arr);printf("arr+1=%p\n", arr + 1);printf("\n");printf("  &arr[0]=%p\n", &arr[0]);printf("&arr[0]+1=%p\n", &arr[0] + 1);printf("\n");printf("  &arr=%p\n", &arr);printf("&arr+1=%p\n", &arr + 1);return 0;
}

在这里插入图片描述

3.3 数组指针的使用

数组指针指向的是数组,那数组指针中存放的数组的地址

#include<stdio.h>
int main()
{int arr[5];int(*p)[5]=&arr;//p的类型是int(*)[5],存放的是存放int类型的数组int* pp[5];//指针数组,pp是数组,存放的是int*类型int* (*ppp) = &pp;//ppp的类型是int*(*)[5],存放的是存放int*类型的数组return 0;
}

3.3.1 打印数组元素

#include<stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }, i = 0;int* p = arr;int(*pp)[10] = &arr;int sz = sizeof(arr) / sizeof(arr[0]);for (i = 0; i < sz; i++){printf("%d ", *(p + i));}printf("\n");for (i = 0; i < sz; i++){printf("%d ", *((*pp) + i));}return 0;
}

3.3.2 打印二维数组元素

#include<stdio.h>void Print1(int arr[3][5], int row, int col)
{for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){printf("%d ", arr[i][j]);}printf("\n");}
}void Print2(int(*p)[5], int row, int col)
{for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){printf("%d ", *(p[i] + j));}printf("\n");}
}
int main()
{int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };Print1(arr, 3, 5);printf("\n");Print2(arr, 3, 5);return 0;
}

3.4 总结:

在这里插入图片描述
数组名arr,表示首元素的地址,二维数组的首元素是二维数组的第一行所以这时传递的arr,其实相当于第一行的地址,是一维数组的地址可以数组指针来接收。

补充:

一维数组传参,形参的部分可以是数组,也可以是指针
二维数组传参,形参的部分可以是数组,也可以是指针

注意:形参写成数组形式是为了让人更容易理解,本质上是指针


四、数组传参和指针传参

4.1 一维数组传参

数组传参的时候,形参可以写成同样数组形式,若是用数组作形参,[ ]里面的值可以省略,也可以随意赋值。传过来的arr是数组首元素地址,所以也可以用一级整形指针来接受。

#include<stdio.h>
void test1(int arr[]);//正确
void test2(int arr[10]);//正确
void test3(int* arr);//正确
int main()
{int arr1[10] = { 0 };
}

实战演练

#include<stdio.h>void test1(int arr[],int sz)
{for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}
}void test2(int arr[10],int sz)
{for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}
}void test3(int* arr, int sz)
{for (int i = 0; i < sz; i++){printf("%d ", *(arr+i));}
}int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int sz = sizeof(arr) / sizeof(arr[0]);test1(arr, sz);printf("\n");test2(arr, sz);printf("\n");test3(arr, sz);return 0;
}

4.2 二维数组传参

void test(int arr[3][5])//ok?
{}
OK
void test(int arr[][])//ok?
{}
NO  二维数组传参,函数形参的设计只能省略行数,不能省略列数
二位数组传参,传的是二维数组第一行的地址,而不是第一行第一个元素的地址
void test(int arr[][5])//ok?
{}
OK
void test(int* arr)//ok?
{}
NO
void test(int* arr[5])//ok?
{}
NO  这是一个存放int* 类型的数组
void test(int(*arr)[5])//ok?
{}
OK  这是一个存放数组的一级指针
void test(int** arr)//ok?
{}
NO
int main()
{int arr[3][5] = { 0 };test(arr);
}

4.3 一维指针传参

void test(int* p)
{}int main()
{int n = 10;test(&n);int* p = &n;test(p);int arr[5] = { 0 };test(arr);return 0;
}

4.4 二维指针传参

void test(int** p)
{}int main()
{int n = 10;int* p=&n;test(&p);int** pp = &p;test(pp);int* arr[5] = { 0 };test(arr);return 0;
}

本次的内容到这里就结束啦。希望大家阅读完可以有所收获,同时也感谢各位铁汁们的支持。文章有问题可以在评论区留言,小羊一定认真认真修改,以后写出更好的文章。
在这里插入图片描述

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

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

相关文章

弄懂软件设计模式(一):单例模式和策略模式

前言 软件设计模式和设计原则是十分重要的&#xff0c;所有的开发框架和组件几乎都使用到了&#xff0c;比如在这小节中的单例模式就在SpringBean中被使用。在这篇文章中荔枝将会仔细梳理有关单例模式和策略模式的相关知识点&#xff0c;其中比较重要的是掌握单例模式的常规写法…

YOLOv5:对yolov5n模型进一步剪枝压缩

YOLOv5&#xff1a;对yolov5n模型进一步剪枝压缩 前言前提条件相关介绍具体步骤修改yolov5n.yaml配置文件单通道数据&#xff08;黑白图片&#xff09;修改models/yolo.py文件修改train.py文件 剪枝后模型大小 参考 前言 由于本人水平有限&#xff0c;难免出现错漏&#xff0c;…

elk安装篇之 Kibana安装

Kibana是一个开源的分析与可视化平台&#xff0c;设计出来用于和Elasticsearch一起使用的。你可以用kibana搜索、查看存放在Elasticsearch中的数据。是es的可视化客户端之一。 一&#xff1a;下载 https://www.elastic.co/cn/kibana 我的es是elasticsearch-7.10.2版本&#x…

Postern配置HTTP和HTTPS的步骤

Postern是一款强大的Android代理工具&#xff0c;它允许您在设备上配置全局代理来实现安全、隐私保护和自由上网。本文将详细介绍如何使用Postern在Android设备上配置HTTP和HTTPS代理&#xff0c;为您提供更便捷的上网体验。 步骤1&#xff1a;下载和安装Postern应用 首先&am…

upload-labs1-21关文件上传通关手册

upload-labs文件上传漏洞靶场 目录 upload-labs文件上传漏洞靶场第一关pass-01&#xff1a;第二关Pass-02第三关pass-03&#xff1a;第四关pass-04&#xff1a;第五关pass-05&#xff1a;第六关pass-06&#xff1a;第七关Pass-07第八关Pass-08第九关Pass-09第十关Pass-10第十一…

Android高通 8.1 老化apk打开摄像头花屏问题

1、最近由于公司VR 3D系统要做双Camera老化测试apk&#xff0c;同时老化4小时需要轮询切换二个摄像头&#xff0c;保证后面camera标定精度数据更准确。 2、一开始我尝试用之前方案移植过去然后同时打开双摄像头 突然发现花屏 如下图所示 3、于是一第一时间想到是不是分辨率不兼…

【vue2第十五章】VueRouter 路由配置(VueRouter)与使用 和 router-link与router-view标签使用

单页面应用 与 多页面应用 单页面应用&#xff08;Single-Page Application&#xff0c;SPA&#xff09;和多页面应用&#xff08;Multi-Page Application&#xff0c;MPA&#xff09;是 Web 应用程序的两种不同架构方式。它们在页面加载和交互方式上有所区别。 单页面应用&a…

【Hive SQL 每日一题】统计用户连续下单的日期区间

文章目录 测试数据需求说明需求实现 测试数据 create table test(user_id string,order_date string);INSERT INTO test(user_id, order_date) VALUES(101, 2021-09-21),(101, 2021-09-22),(101, 2021-09-23),(101, 2021-09-27),(101, 2021-09-28),(101, 2021-09-29),(101, 20…

Ubutnu允许ssh连接使用root与密码登录

文章目录 1. 修改sshd_config2. 设置root密码3. 重启SSH服务 1. 修改sshd_config 修改/etc/ssh/sshd_config文件&#xff0c;找到 #Authentication&#xff0c;将 PermitRootLogin 参数修改为 yes。如果 PermitRootLogin 参数被注释&#xff0c;请去掉首行的注释符号&#xff…

激光焊接汽车尼龙塑料配件透光率测试仪

激光塑性成型技术是近年来塑性加工界出现的一种新技术。通常塑料主要是通过加热加压依赖模具成型。这对于单品种、大批量生产是有效的&#xff1b;而对于各种不同形状的塑料制件则需要昂贵的模具‚装置也较庞大。 高度聚焦的激光束垂直照射在待变形的板料上‚由于塑料直接吸收激…

【MySQL】事务 详解

事务 详解 一. 为什么使用事务二. 事务的概念三. 使用四. 事务的特性原子性&#xff08;Atomicity&#xff09;一致性&#xff08;Consistency&#xff09;隔离性&#xff08;Isolation&#xff09;持久性&#xff08;Durability&#xff09; 五. 事务并发所带来的问题脏读问题…

MT4移动端应用指南:随时随地进行交易

如今&#xff0c;随着科技的不断发展&#xff0c;我们可以随时随地通过手机进行各种操作&#xff0c;包括进行金融交易。本文将为大家介绍一款优秀的金融交易软件——MT4&#xff08;可在mtw.so/6gwPno这点下&#xff09;移动端应用&#xff0c;并提供详细的使用指南&#xff0…