笔记-指针的进阶

news2024/11/20 12:40:58

1.字符指针

char arr[] = "hello bit."

char * p = arr

这里p指向的是数组的首元素,arr数组是可以修改的。

(const)char * pstr = "hello bit."

这里的字符串是常量字符串,不能修改。

这里有一个面试题:

#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");

  else 

       printf("str1 and str2 are not same\n");

  

  if(str3 == str4)

       printf("str1 and str2 are same\n");

  else 

       printf("str1 and str2 are not same\n");

  return 0;

这里最终的输出结果是:

 

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

2.指针数组

指针数组就是一个存放指针的数组

int * arr1 [10];        //整型指针的数组

char * arr2 [4];       //字符指针的数组

char **arr3 [5];      //二级字符指针的数组

3.数组指针

数组指针就是一个指向数组的指针

int (*p1) [10];   //这是一个数组指针,指针指向一个整型数组, 这个数组有10个元素。

 注意:这里的数组指针存放的不是数组的首元素地址,而是一整个数组的地址。

相当于

int arr[10];

int (*p1)[10] = &arr;    //注意这里是对数组名取地址,而不是数组名。

4.数组参数、指针参数

4.1一维数组传参

#include <stdio.h>

//一维数组传参时,形参可以是数组也可以是一级指针。

void test(int arr[]) {}                  √

void test(int arr[10]){}               √

void test(int * arr){}                   √

//指针数组传参时,形参可以是指针数组,也可以是二级指针。

void test2(int * arr[20]){}          √

void test2(int ** arr){}               √

4.2二维数组传参

#include <stdio.h>

//二维数组传参时,形参可以是数组指针,也可以是二维数组。

void test(int arr[3][5]){}              √

void test(int arr[][]) {}                 ×  

void test(int arr[][5]) {}               √

void test(int  (*arr)[5]){}             √

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

二级指针变量

一级指针变量的地址

数组指针

5.函数指针

先看一段代码:

#include <stdio.h>

void test()

{

   printf("hehe\n");

int main()

{

  printf("%p\n",test);        

  printf("%p\n",&test);

}

 这里的输出结果是:

所以我们得出结论:

函数名和&函数名都代表函数地址,没有区别。

函数指针的使用:

#include <stdio.h>

int Add(int x, int y)

{

    return x+y;

}

int main()

{

     int (*pf)(int ,int) = Add;            //可以直接将函数名赋值过去

     int ret = (*pf)(3,5);                   //可以将*省略,直接写成pf(3,5)。

     printf("%d\n",ret);

}

结果:

6.函数指针数组

要把函数的地址存到一个数组中,那这个数组就叫做函数指针数组,那函数指针的数组应该怎么定义呢?

int (*parr1 [10]) ( )

拆解一下:这里(小黄)parr1[10]表示它是一个数组,数组的每个元素都是什么类型呢?

一般一个数组声明除了数组名和元素个数之外就是数组的元素类型了,所以这里的小绿(函数指针)就是类型。

函数指针数组的用途:转移表

7.指向函数指针数组的指针

指向函数指针数组的指针是一个指针,指向一个数组,数组的每个元素都是一个函数指针。

int (*pf) (int, int) = Add;                               //函数指针

int (*pf [4]) (int, int) = {Add, sub};                //指针数组,数组的每个元素都是一个函数指针

int (* (*pf) [4] ) (int ,int);                               //数组指针,指向的是一个函数指针数组

 

8.回调函数

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为函数传递给另一个函数,当这个指针被用来调用其指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行相应。

指针和数组笔试题解析:

注意:strlen计算的是'\0'之前的字符,并且只能接收地址参数,而sizeof计算的有效字符,可以传地址,也可以传值,'\0'算在其中。

一维数组:

int a [ ] = {1,2,3,4};

printf ("%d\n",sizeof(a));        //16

printf("%d\n",sizeof(a+0));      //4

printf("%d\n",sizeof(*a));         //4(*a=a[0])

printf("%d\n",sizeof(a+1));      //4

printf("%d\n",sizeof(a[1]));      //4

printf("%d\n",sizeof(&a));        // 4/8 取出的是数组的地址,只要是地址,都是4/8

printf("%d\n",sizeof(*&a));       //16( sizeof(a) )

printf("%d\n",sizeof(&a+1));    // 4/8

printf("%d\n",sizeof(&a[0]));    //4/8

printf("%d\n",sizeof(&a[0]+1));  //4/8

 字符数组:

char arr[] = {'a', 'b', 'c' , 'd', 'e', 'f'};

 printf("%d\n",sizef(arr));                    //6

 printf("%d\n",sizef(arr+0));                //4/8

 printf("%d\n",sizef(*arr));                   //1

 printf("%d\n",sizef(arr[1]));                //1

 printf("%d\n",sizef(&arr));                 //4/8

 printf("%d\n",sizef(&arr+1));             //4/8

 printf("%d\n",sizef(&arr[0]+1));         //4/8

 printf("%d\n",strlen(arr));                  //不确定(>=6),strlen统计的是'\0'之前的字符个数

 printf("%d\n",strlen(arr+0));             //不确定(>= 5)

 printf("%d\n",strlen(*arr));  //将arr[0]传进来,字符ASCII码被强制当作地址,造成非法访问。

 printf("%d\n",strlen(arr[1]));            //同上

 printf("%d\n",strlen(&arr));              //不确定

printf("%d\n",strlen(&arr+1));          //跳过字符串,也是不确定

             

printf("%d\n",strlen(&arr[0]+1));      //不确定           

         

char arr[] = "abcdef"

printf("%d\n",sizeof(arr));                //7(加上'\0')  

printf("%d\n",sizeof(arr+0));            //4/8

printf("%d\n",sizeof(*arr));               //1

printf("%d\n",sizeof(arr[1]));            //1

printf("%d\n",sizeof (&arr));            //4/8

printf("%d\n",strlen(&arr+1));         //4/8       

printf("%d\n",sizeof(&arr[0]+1));    //4/8            

printf("%d\n",strlen(arr));               //6

printf("%d\n",strlen(arr+0));          //6

printf("%d\n",strlen(*arr));            //将arr[0]强制转换成地址变量,造成地址的非法访问。  

printf("%d\n",strlen(arr[1]));        //非法访问

 

printf("%d\n",strlen(&arr));         //6

printf("%d\n",strlen(&arr+1));     //跳过整个数组,包括'\0',所以是随机值。  

printf("%d\n",strlen(&arr[0]+1));  //5

  

(const) char *p = "abcdef";              

printf("%d\n",sizeof(p));            //4/8

printf("%d\n",sizeof(p+1));       //4/8

printf("%d\n",sizeof(*p));          //1

printf("%d\n",sizeof(p[0]));       //1

  

printf("%d\n",sizeof(&p));       //4/8

printf("%d\n",sizeof(&p+1));   //4/8 

printf("%d\n",sizeof(&p[0]));   //4/8

 

printf("%d\n",strlen(p));          //6

 

printf("%d\n",strlen(p+1));     //5

printf("%d\n",strlen(*p));       //非法访问

  

printf("%d\n",strlen(p[0]));    //非法访问

  

printf("%d\n",strlen(&p);      //随机值 (无法确定'\0'的位置)

printf("%d\n",strlen(&p+1)); //随机值

printf("%d\n",strlen(&p[0]+1)); //5

二维数组:

int a[3][4] = {0};

printf("%d\n",sizeof(a));             //48

printf("%d\n",sizeof(a[0][0]));     //4

printf("%d\n",sizeof(a[0]));          //16

printf("%d\n",sizeof(a[0]+1));      //4/8

printf("%d\n",sizeof(*(a[0]+1)));  //4

printf("%d\n",sizeof(a+1));          //4/8

printf("%d\n",sizeof(*(a+1)));      //4

printf("%d\n",sizeof(&a[0]+1));    //4/8

printf("%d\n",sizeof(*(&a[0]+1)));   //16

printf("%d\n",sizeof(*a));             //16

printf("%d\n",sizeof(a[3]));           //16 (sizeof内部的表达式是不会计算的,不会越界。)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LeetCode_二叉树_中等_113.路径总和 II

目录 1.题目2.思路3.代码实现&#xff08;Java&#xff09; 1.题目 给你二叉树的根节点 root 和一个整数目标和 targetSum &#xff0c;找出所有从根节点到叶子节点路径总和等于给定目标和的路径。 叶子节点是指没有子节点的节点。 示例 1&#xff1a; 输入&#xff1a;root…

网络基础知识(1)——从OSI七层模型和TCP/IP说起

网络通信概述 网络通信本质上是一种进程间通信&#xff0c;是位于网络中不同主机上的进程之间的通信&#xff0c;属于 IPC 的一种&#xff0c; 通常称为 socket IPC&#xff0c;如图中所示。所以网络通信是为了解决在网络环境中&#xff0c;不同主机上的应用程序之间的通信问题…

U盘上的文件删除了可以恢复吗 U盘上的文件怎么在电脑上恢复

随着数据时代的到来&#xff0c;人们使用U盘来存储和传输文件已经成为一种普遍的方式。然而&#xff0c;有时候人们会不小心将重要的文件从U盘上删除&#xff0c;或者由于其他原因导致文件丢失&#xff0c;这会给人们带来很多麻烦和不必要的损失。因此&#xff0c;在这篇文章中…

华为OD机试(1-20)老题库解析Java源码系列连载ing

华为OD机试算法题新老题库练习及源码 老题库1.敏感字段加密2.IPv4地址转换成整数3.VLAN资源池4. 求字符串中所有整数的最小和5.求满足条件的最长子串的长度6.字符串分割7.一种字符串压缩表示的解压8.矩阵最大值9.单词接龙10.找出符合要求的字符串子串11.字符串加密12.英文输入法…

指定目标对角线创建值全是1的下三角矩阵numpy.diagflat()方法

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 指定目标对角线 偏离主对角线的距离k 创建值全是1的下三角矩阵 numpy.tri() 选择题 关于以下代码说法错误的一项是? import numpy as np print("【执行】a np.tri(3, 3, 0, dtypeint)…

三十二、VPN技术概述——GRE、IPSec、MPLS vpn

文章目录 vpn 简介用途优缺 一、GRE-VPN1、基础配置步骤&#xff1a;2、可选配置 二、IPSEC-VPN 概述1、IPSes 特性2、IPSec 架构3、IPSec 数据封装 三、GRE OVER IPSEC VPN 配置1、配置2、注意 vpn 简介 vpn&#xff1a;virtual private network&#xff08;虚拟专用网络&…

Prompt都不需要了,动动手就能玩多模态对话系统,iChat来啦!

作者 | 智商掉了一地 近日有很多团队基于用户友好的 ChatGPT 进行再创作&#xff0c;其中不乏有比较亮眼的成果。InternChat工作强调了用户友好性&#xff0c;这是通过超越语言的方式&#xff08;光标与手势&#xff09;与聊天机器人交互来进行多模态任务的。InternChat 的命名…

MATLAB基础入门:语法、数据类型和常用函数

MATLAB是一种非常强大的数学计算软件&#xff0c;广泛应用于工程、科学、金融和其他领域的计算分析中。如果您刚开始学习MATLAB&#xff0c;那么这篇文章就是为您准备的。在这篇文章中&#xff0c;我们将介绍MATLAB的基础语法、数据类型和常用函数&#xff0c;以帮助您快速入门…

容器技术Docker

什么是容器 Linux容器是与系统其他部分隔离开的一系列进程&#xff0c;从另一个系统镜像运行&#xff0c;并由该镜像提供支持进程所需的全部文件。 容器镜像包含了应用的所有依赖项&#xff0c;因而在从开发到测试再到生产的整个过程中&#xff0c;它都具有可移植性和一致性。…

C++ | std::bind

C | std::bind 文章目录 C | std::bindstd::bind函数原型bind函数参数返回对象的类型&#xff1a; 实战1.普通函数/类成员函数/类成员变量2.模板函数3.lambda表达式 Reference std::bind函数原型 // 无返回值&#xff08;1&#xff09; template <class Fn, class... Args&…

OpenHarmony下如何打印C/C++调用堆栈

普法OpenHarmony下如何打印C/C调用堆栈 引言 各位大姐&#xff0c;老妹&#xff0c;兄弟是否在OpenHarmony开发移植过程中有过如下烦恼呢&#xff1f;想跟踪源码探寻相关代码逻辑的时候&#xff0c;当面对代码分支逻辑太多&#xff0c;太复杂&#xff0c;打调试信息进行追踪已经…

Mach-O

看看逆向过程中&#xff0c;经常遇见的Mach-O文件类型&#xff1a; MH_OBJECT&#xff0c;这种类型的文件有目标文件(.o)、静态库文件(.a) &#xff08;静态库文件就是N个.o文件合并在一起的&#xff09; MH_EXECUTE&#xff0c;可执行文件&#xff0c;例如上面说的Super文件 …

如何选择一款好的护眼台灯给孩子用?儿童护眼台灯推荐

所以也想要分享给大家&#xff0c;那么热爱看书的你&#xff0c;是否有时候会因为光源的问题而烦恼呢&#xff1f;房间所用的大灯虽然亮度足够&#xff0c;但太过于分散的光&#xff0c;让眼睛在长期聚精会神后&#xff0c;有了红肿干涩&#xff0c;酸痛模糊的感觉。而专用的台…

界面控件DevExpress Blazor UI v22.2 - 折叠组件、数据编辑器升级增强

DevExpress拥有.NET开发需要的所有平台控件&#xff0c;包含600多个UI控件、报表平台、DevExpress Dashboard eXpressApp 框架、适用于 Visual Studio的CodeRush等一系列辅助工具&#xff0c;该组件拥有众多新产品和数十个具有高影响力的功能&#xff0c;可为桌面、Web和移动应…

远程桌面基本原理

远程桌面基本原理 远程桌面是一种技术&#xff0c;它允许用户通过互联网或局域网远程访问另一台计算机的桌面。这种技术可以让用户在不同的地方使用同一台计算机&#xff0c;或者在同一地方使用不同的计算机。远程桌面技术在现代计算机应用中发挥着重要的作用&#xff0c;本文将…

达索的CAD绘图软件DraftSight 2023版本下载与安装配置教程

目录 前言一、​安装前准备二、DraftSight安装三、使用配置总结 前言 Dassault Systemes公司的DraftSight软件是一款功能强大的2D CAD绘图软件&#xff0c;可以帮助用户快速、准确地创建和编辑各种类型的图形。它的用户界面简单易用&#xff0c;支持多种文件格式&#xff0c;包…

C++ | function

C | function 文章目录 C | function引言实战1. 模板类声明2.普通函数/Lambda表达式/仿函数/类成员函数3.函数指针/模板函数/模板函数对象4.静态函数/类模板静态函数/模板类成员函数/类成员函数5. copy/move Reference 引言 程序设计时&#xff0c;经常需要使用回调函数&#…

多语言支持-唯一客服系统文档中心

客服系统支持多语种展示&#xff0c;比如&#xff1a;中文&#xff0c;英文&#xff0c;繁体&#xff0c;日语&#xff0c;韩语&#xff0c;俄语等&#xff0c;并且可以扩展各种小语种 语种展示的优先级 首先&#xff0c;按照url参数中指定的lang参数 其次&#xff0c;查询loca…

Open5gs学习笔记

目录 1.用户面和控制面分离 最近想在liunx模拟机上运行Open5GSUERANSIM来学习5G信令流程。 1.用户面和控制面分离 open5GS的quickstart提及By having the control and user planes physically separated like this, it means you can deploy multiple user plane servers in …