C语言 — 指针进阶篇(上)

前言

指针基础篇回顾可以详见: 指针基础篇(1)指针基础篇(2)

指针进阶篇分为上下两篇,上篇介绍1 — 4,下篇介绍5 — 6

  1. 字符指针
  2. 数组指针
  3. 指针数组
  4. 数组传参和指针传参
  5. 函数指针
  6. 函数指针数组
  7. 指向函数指针数组的指针
  8. 回调函数

文章目录

  • 前言
  • 一、字符指针
    • 1. 字符指针用法
    • 2. 字符指针面试题
  • 二、指针数组
    • 1. 不同类型的指针数组
  • 三、数组指针
    • 1. 数组指针定义
    • 2. &数组名与数组名的区别
    • 3. 数组指针的使用
  • 四、数组传参和指针传参
    • 1. 一维数组传参
    • 2. 二维数组传参
    • 3. 一级指针传参
    • 4. 二级指针传参
  • 五、总结

一、字符指针

在基础篇中简单介绍过字符指针

1. 字符指针用法

一般使用

int main()
{char ch = 'a';char* p = &ch;*p = 'c';return 0;
}

另一种用法

#include<stdio.h>
int main()
{const char* psr = "hello word";printf("%s\n", psr);return 0;
}

输出结果
在这里插入图片描述

输出的结果是hello word,字符串的首字符的地址存放在字符指针psr
即意思是把一个常量字符串的首字符h的地址存放在指针变量 psr

2. 字符指针面试题

演示代码

#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("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;
}

输出结果
在这里插入图片描述
结论

这里str3和str4指向的是一个同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当几个指针指向同一个字符串的时候,他们实际会指向同一块内存
但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。
所以str1和str2不同,str3和str4相同。

二、指针数组

在指针基础篇中提到过,指针数组就是存放指针的数组

1. 不同类型的指针数组

int * arr1[10]; 		//整形指针数组 ,里面存放整形指针
char * arr2[10];		//一级字符指针数组,里面存放字符指针
char ** arr3[10];		//二级字符指针数组,里面存放二级字符指针

三、数组指针

1. 数组指针定义

数组指针区别于上面的指针数组,数组指针是指针指针数组是数组。


数组指针和指针数组是两个不同的概念。

数组指针是指一个指向数组的指针变量。它可以用于访问数组元素,也可以作为函数参数传递,可以定义如下:

int (*arr_ptr)[N]; // 定义一个指向长度为 N 的整型数组的指针

这个指针变量可以指向长度为 N 的整型数组,可以通过以下方式初始化:

int arr[N] = {1, 2, 3, 4, 5};
int (*arr_ptr)[N] = &arr; // 指向数组arr的指针

指针数组是指一个包含指针的数组。它可以用来存储一组指针,也可以通过指针访问数组元素,可以定义如下:

int *ptr_arr[N]; // 定义一个包含N个指向整型的指针的数组

这个数组包含 N 个指针变量,每个指针变量可以指向一个整型变量,可以通过以下方式初始化:

int a = 10, b = 20, c = 30;
int *ptr_a = &a, *ptr_b = &b, *ptr_c = &c;
int *ptr_arr[] = { ptr_a, ptr_b, ptr_c };

以上都是基本的定义和初始化方式,具体使用还需要根据具体场景和需求进行操作。

2. &数组名与数组名的区别

演示代码

#include <stdio.h>
int main()
{int arr[10] = {0};printf("%p\n", arr);printf("%p\n", &arr);return 0;
}

输出结果
在这里插入图片描述
结论
总所周知,arr是数组名,数组名是首元素的地址
由输出结果得arr和&arr的输出结果相同,其实这两者是存在区别的


在上面的基础上我们对arr和&arr进行+1操作

演示代码

#include <stdio.h>
int main()
{int arr[10] = { 0 };printf("arr = %p\n", arr);printf("arr+1 = %p\n", arr + 1);printf("&arr= %p\n", &arr);printf("&arr+1= %p\n", &arr + 1);return 0;
}

输出结果

在这里插入图片描述

结论

由代码得,arr和&arr输出的值是一样的,但意义不同
&arr表示的是数组的地址,而不是数组首元素的地址
在这里插入图片描述

arr表示首元素地址,首元素地址+1,就是跳过一个元素的指针,( int是4个字节 )就是+4
&arr表示数组地址,数组地址+1,就是跳过整个数组的大小,所以&arr+1对于&arr的差值是40

3. 数组指针的使用

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

代码演示

#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };int(*p)[10] = &arr;//(*p)表示p是一个指针变量,[10]表示有10个元素return 0;
}

(*p)表示p是一个指针变量,[10]表示有10个元素


数组指针的使用举例

#include <stdio.h>
void print_arr1(int arr[3][5], int row, int col)
{int i = 0;for(i=0; i<row; i++){for(j=0; j<col; j++){printf("%d ", arr[i][j]);}printf("\n");}
}
void print_arr2(int (*arr)[5], int row, int col)
{int i = 0;for(i=0; i<row; i++){for(j=0; j<col; j++){printf("%d ", arr[i][j]);}printf("\n");}
}
int main()
{int arr[3][5] = {1,2,3,4,5,6,7,8,9,10};print_arr1(arr, 3, 5);//数组名arr,表示首元素的地址//但是二维数组的首元素是二维数组的第一行//所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址//可以数组指针来接收print_arr2(arr, 3, 5);return 0;
}

四、数组传参和指针传参

写代码时(以往写冒泡排序时)需要把数组或指针传给函数,下面介绍函数的参数应该如何设计


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);
}

总结:以上传参都是正确的


2. 二维数组传参

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  形参是指针数组
{}
void test(int (*arr)[5])//ok   形参是数组指针
{}
void test(int **arr)	//NO  二级指针
{}
int main()
{int arr[3][5] = {0};test(arr);
}

总结:二维数组传参,函数形参的设计只能省略第一个[ ]的数字。因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。这样才方便运算。


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};int *p = arr;int sz = sizeof(arr)/sizeof(arr[0]);//一级指针p,传给函数print(p, sz);return 0;
}

总结:传过去的参数和形参是匹配的上即可


4. 二级指针传参

#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;
}

总结:传pp和&p都可以,相互对应即可

当函数的参数为二级指针的时候,可以接收什么参数?

void test(char **p)
{}
int main()
{char c = 'b';char*pc = &c;char**ppc = &pc;char* arr[10];	 test(&pc);	 //OKtest(ppc);	 //OKtest(arr);   //OKreturn 0;
}

五、总结

本文介绍了字符指针、数组指针、指针数组、数组传参和指针传参。

数组指针是指针,指针数组是数组

arr表示首元素地址,首元素地址+1,就是跳过一个元素的指针,( int是4个字节 )就是+4
&arr表示数组地址,数组地址+1,就是跳过整个数组的大小,所以&arr+1对于&arr的差值是40

二维数组传参,函数形参的设计只能省略第一个[ ]的数字。因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。这样才方便运算。


如这篇博客对大家有帮助的话,希望 三连 支持一下 !!! 如果有错误感谢大佬的斧正 如有 其他见解发到评论区,一起学习 一起进步。

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

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

相关文章

Java线程状态与状态转换

前言 在Java中&#xff0c;线程是多任务处理的基本单位&#xff0c;它可以并行执行多个任务。线程的状态描述了线程在其生命周期中的不同阶段。Java线程的状态可以分为以下几种&#xff1a; 线程状态 状态解释新建状态&#xff08;New&#xff09;线程被创建但尚未启动就绪状…

复习第五课 C语言-初识数组

目录 【1】初识数组 【2】一维数组 【3】清零函数 【4】字符数组 【5】计算字符串实际长度 练习&#xff1a; 【1】初识数组 1. 概念&#xff1a;具有一定顺序的若干变量的集合 2. 定义格式&#xff1a; 数组名 &#xff1a;代表数组的首地址&#xff0c;地址常量&…

“AI+教育”:景联文科技高质量教育GPT题库助力教学创新

去年年底&#xff0c;OpenAI推出ChatGPT&#xff0c;掀起AI热潮&#xff0c;教育作为“AI”应用落地的关键场景&#xff0c;再次受到广泛关注。 “AI教育”的快速发展&#xff0c;是受到技术、需求和政策三重因素共同驱动的结果。 在技术方面&#xff0c;随着人工智能技术的不断…

【专题速递】在线K歌、云化XR、咔嚓剪辑和FFmpeg直播能力更新计划

// 在线K歌的技术方案选型有哪些&#xff1f;对于沉浸式XR我们又有什么新的思考&#xff1f;高性能低依赖的剪辑视频需要具备什么技术&#xff1f;7月29日LiveVideoStackCon2023上海站客户端体验与性能优化专场&#xff0c;为您解答。 客户端体验与性能优化 客户端作为直接面…

基于Python编写一个B站全自动抽奖的小程序

本文将利用Python编写一个B站全自动抽奖的小程序&#xff0c;可以实时监控自己关注的UP主&#xff0c;如果关注的UP主中有人发布了抽奖的动态&#xff0c;就自动参与这个抽奖。这样就能不错过任何一个可以暴富的机会了。需要的可以参考一下 导语 应好友邀请&#xff0c;帮他写…

Qt 桌面系统设计

文章目录 前言一、项目介绍二、界面布局三、按键图标四、桌面背景五、实现led功能总结 前言 这篇文章介绍 一个Qt 桌面系统的项目&#xff0c;大家可以在此基础上加以改进&#xff0c;实现更多的功能。 一、项目介绍 可以看到 这个桌面系统上分为两部分&#xff0c;左边是 三个…

C++虚函数学习

VC6新建一个单文档工程&#xff1b; 添加一个一般类&#xff1b; 生成的Shape.cpp保持不变&#xff1b; #include "Shape.h"#ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]__FILE__; #define new DEBUG_NEW #endif// // Construction/Destruction //Shap…

基于C/S架构工作原理序号工作步骤和理论的区别

基于C/S架构工作原理序号工作步骤和理论的区别 SSH 概念 对称加密linux 系统加密&#xff0c;就是加密和揭秘都是使用同一套密钥。 非对称加密有两个密钥&#xff1a;“私钥”和“公钥”。私钥加密后的密文&#xff0c;只能通过对应的公钥进行揭秘。而通过私钥推理出公钥的…

MyBatis 的架构

MyBatis 的架构 MyBatis 是一个基于 Java 的持久层框架&#xff0c;可以将 SQL 语句和 Java 代码进行分离&#xff0c;通过 XML 或注解的方式配置 SQL 语句并执行&#xff0c;从而实现数据访问的功能。MyBatis 的架构包括以下几个部分&#xff1a; SqlSessionFactory&#xff…

ElasticSearch入门教程--集群搭建和版本比较

文章目录 一、ElasticSearch 集群二、Elasticsearch的核心概念2.1、分片&#xff08;Shards&#xff09;2.2、副本&#xff08;Replicas&#xff09;2.3、路由计算2.4、倒排索引 三、Kibana简介四、Spring Data ElasticSearch 一、ElasticSearch 集群 Elasticsearch 集群有一个…

CAD2021安装教程适合新手小白【附安装包和手册】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、下载文件二、使用步骤1.安装软件前&#xff0c;断开电脑网络&#xff08;拔掉网线、关闭WIFI&#xff09;2、鼠标右击【AutoCAD2021(64bit)】压缩包选择【解…

无线电音频-BPA600蓝牙协议分析仪名词解析

1 介绍 2 Baseband基带分析 (1)Delta 是什么含义? "Delta" 有多个含义,取决于上下文。以下是常见的几种含义: 希腊字母:Delta&#x