C语言-指针_02

指针-02

1. 指针的指针

概念:指针变量中存储的是指针的地址,又名 二维指针

语法:

数据类型 **p;

示例:

#include <stdio.h>
int main(int argc, char const *argv[])
{int num = 10;int *p1 = &num;int **p2 = &p1;printf("*p1是: %d\n", *p1);         //*p1是: 10printf("p1的值是: %p\n", p1);       //p1的值是: 0x7ffd1a6bff0printf("p1的地址是: %p\n", &p1);    //p1的地址是: 0x7ffd1a6bff08printf("p2的值是: %p\n", p2);       //p2的值是: 0x7ffd1a6bff08printf("p2的地址是: %p\n", &p2);    //p2的地址是: 0x7ffd1a6bff10return 0;
}

在这里插入图片描述

2. 指针与const

2.1 指针常量 - (int * const p)

概念:

本质是一个常量

  • 该指针常量 不能修改指向的地址(就是不能指向其他变量)
  • 但是可以修改指向地址中的值

注意:数组就是一个指针常量。

语法:

数据类型 * const 指针名称

例:

void fun01()
{int num = 10;// int *p = &num;// int num02 = 20;// p = &num02;// printf("p = %p\n", p);//指针常量//p被const修饰,int * const p = &num;int num03 = 30;// p = &num03;  //指针指向的地址不可修改*p = 40;        //但是指针指向的地址的值可以修改printf("*p = %d\n", *p); //*p = 40
}

2.2 常量指针 - (const int *p)

概念:

指向常量(值不可修改)指针,本质是一个指针

  • 不能修改其指向地址的值 ,也就是 不能通过指针改变其指向的地址中的数据
  • 但是可以修改其指向的地址,也就是 可以改变其存储的地址

例:

void fun02()
{int num = 10;//常量指针//指针被const修饰,// int const *p = &num;const int *p = &num;printf("p修改前的地址%p\n", p);  //p修改前的地址0x7fff0b95ff58int num04 = 30;p = &num04;  //指针指向的地址可以修改// *p = 40;  //但是指针指向的地址的值不可以修改printf("p修改后的地址%p\n", p);  //p修改后的地址0x7fff0b95ff5c
}

2.3 常量指针常量 - (const int * const p)

概念:

指向的地址 和 只想地址中的 都不可以修改

语法:

数据类型 const * const 指针名称
或 
const 数据类型 * const 指针名称

例:

void fun03()
{int num = 10;//常量指针常量//指针和指针变量p都被const修饰,const int * const p = &num;int num02 = 40;// p = &num02; //指针指向的地址不可以被修改// *p = 50;    //指针指向的地址的值也不可以修改
}

3. 指针与数组元素

概述:

数组:是多个相同类型的变量的集合,每个变量占内存空间,都有 地址编号指针变量 当然 可以存放数组元素的地址

注意:

  1. 只有 两个相同类型 的指针指向 同一个数组的元素 的时候,比较大小才有意义;

  2. 指向前面元素 的指针 小于 指向 后面元素 的指针

  3. 数组就是数组中存储的 第一个元素的地址

  4. c语言中数组的本质是一个 指针常量

    • 不可以修改指针的地址,
    • 但是可以修改该指针指向地址的值

示例1:

void fun01()
{int nums[] = {1,3,5,7,9,2,4,6,8,10};int *p = &nums[3];printf("*p = %d\n", *p);       //*p = 7printf("*(p+1) = %d\n", *(p+1));       //*(p+1) = 9printf("*(p+2) = %d\n", *(p+2));       //*(p+2) = 2printf("*(p-1) = %d\n", *(p-1));       //*(p-1) = 5printf("*(p-2) = %d\n", *(p-2));       //*(p-2) = 3for (int i = 0; i < 10; i++){printf("%p\n", &nums[i]);}
}/*
0x7ffc007c1610
0x7ffc007c1614
0x7ffc007c1618
0x7ffc007c161c
0x7ffc007c1620
0x7ffc007c1624
0x7ffc007c1628
0x7ffc007c162c
0x7ffc007c1630
0x7ffc007c1634
*/

示例2:

void fun02()
{int nums[] = {1,3,5,7,9,2,4,6,8,10};int *p = &nums[0];for (int i = 0; i < 10; i++){printf("nums[%d] = %d\n", i, *(p++));}
}/*
nums[0] = 1
nums[1] = 3
nums[2] = 5
nums[3] = 7
nums[4] = 9
nums[5] = 2
nums[6] = 4
nums[7] = 6
nums[8] = 8
nums[9] = 10
*/

示例3:

void fun03()
{int nums[] = {1,3,5,7,9,2,4,6,8,10};int *p1 = &nums[0];int *p2 = &nums[1];if (p1 < p2){printf("p1在p2的前面\n");}else{printf("p1在p2的后面\n");}
}
//p1在p2的前面

示例4:

void fun04()
{int nums[] = {1,3,5,7,9,2,4,6,8,10};//数组名就是数组中存储的第一个元素的地址printf("nums = %p\n",nums);         //nums = 0x7ffe6b558c30printf("nums[0]= %p\n",&nums[0]);   //nums[0]= 0x7ffe6b558c30
}

示例5:

void fun05()
{int nums[] = {1,3,5,7,9,2,4,6,8,10};int *p = nums;for (int i = 0; i < 10; i++){// printf("nums[%d] = %d\n", i, *(p++));// printf("nums[%d] = %d\n", i, *(p+i));// printf("nums[%d] = %d\n", i, nums[i]);// printf("nums[%d] = %d\n", i, p[i]);printf("nums[%d] = %d\n", i, *(nums+i));//c语言中数组的本质是一个 指针常量//不可以修改指针的地址,但是可以修改该指针指向地址的值// printf("nums[%d] = %d\n", i, *(nums++));  //报错}}

4. 指针与数组

4.1 数组名

数组名 其实是数组中 首元素的地址 。

例:

void fun04()
{int nums[] = {1,3,5,7,9,2,4,6,8,10};//数组名就是数组中存储的第一个元素的地址printf("nums = %p\n",nums);         //nums = 0x7ffe6b558c30printf("nums[0]= %p\n",&nums[0]);   //nums[0]= 0x7ffe6b558c30
}

4.2 数组指针

数组名可以赋值给一个指针变量,此时该指针指向一个数组,被称为 数组指针,其本质是一个 指针

语法:

  • 指向一维数组语法
    • 数据类型 * 指针名;
  • 指向二维数组指针的语法
    • 数组类型 (*指针名)[二维数组中一维数组的长度];
  • 指向三维数组指针的语法
    • 数组类型 (*指针名)[三维数组中二维数组的长度][二维数组中一维数组的长度];

示例:

void fun06()
{//数组指针//概念:指向数组的指针,本质是一个指针int nums[] = {1,3,5,7,9,2,4,6,8,10};int *p1 = nums;int nums02[2][4] = {1,2,3,4,5,6,7,8};int (*p2)[4] = nums02;int nums03[2][3][4] = {0};int (*p3)[3][4] = nums03;
}

4.3 指针数组

指针变量是一个变量,数组是可以存储多个类型形容的变量的勇容器,故 数组可以存储多个指针变量,此时该数组 被称为 指针数组,其本质是一个 数组

语法:

数据类型 * 数组名[长度];

例:

void fun07()
{int a = 10,b = 20,c = 30;int *p1 = &a;int *p2 = &b;int *p3 = &c;//指针数组//存储指针的数组,本质是一个数组int *nums[3] = {p1, p2, p3};
}

4.4 字符数组与字符串指针的区别

字符数组:内存(栈、静态全局区)中开辟了一段空间存放字符串,将其首元素地址赋值给 数组名,是个 指针常量

字符串指针:

  • 如果指向 在 文字常量区 中存放 字符串,会将 字符串首地址赋值给 指针变量,此时该指针是个 常量指针

  • 如果指向 栈、静态全局区中存放的字符数组,那么则是一个 普通的指针变量,值和地址都可以修改。

    示例1:

void fun08()
{//str01的内存地址在栈区//str01是一个数组,所以是一个指针常量//指针常量可以修改其地址中的值//指针常量不可以修改其指向的地址char str01[] = "hello";str01[0] = 'H';printf("str01=%s\n",str01);     //str01=Hello//str01 = "world";			//报错,不能指向另外的地址//str02的内存地址在文字常量区//常量指针//指针指向的地址可以修改//指针指向的地址中的元素不可修改char * str02 = "hello";printf("str02修改前的地址%p\n",str02);      //str02修改前的地址0x400d28str02 = "world";printf("str02修改后的地址%p\n",str02);      //str02修改后的地址0x400d4//str02[0] = 'W';     //段错误 (核心已转储)
}

示例2:

void fun09()
{//字符数组char str01[] = "hello";//指向 栈、静态全局 区中存放的字符数组char *str03 = str01;printf("str03修改内容前%s\n",str03);  //tr03修改内容前hellostr03[0] = 'H';printf("str03修改内容后%s\n",str03);  //str03修改内容后Hellostr03 = "world";  printf("str03修改地址后%s\n",str03);  //str03修改地址后world
}

示例3:

void fun10()
{char names[][50] = {"boboy","tom","jerry","zhangsan","lisi"};//指针数组:存储的是这些值的首地址char *ns[50] = {"boboy","tom","jerry","zhangsan","lisi"};//数组指针// char (*nss)[50] = names;char (*nss)[50] = {"boboy","tom","jerry","zhangsan","lisi"};
}

5. 函数与指针

5.1 函数名就是函数地址

函数名本身就是函数在代码区存储该函数的地址,故 可以赋值给一个指针变量,但是因为其在代码区的地址不可修改,所以该指针是一个指针常量

语法:

  • 函数指针的定义初始化

    返回值类型 (*指针名称)(指向的函数的形参列表的数据类型) = 函数名;
    

    注意:

    • 指向的函数的形参列表的数据类型可以忽略不写
  • 调用其指向的函数

    指针名(实参列表);变量名 = 指针名(实参列表);
    

    注意:

    • 实参列表可以忽略不写

示例1:函数名本身就是函数在代码区存储 该函数的地址

#include <stdio.h>
void test01()
{printf("test01被调用了!");
}
void fun01()
{printf("%p\n", test01);  //0x400526
}int main(int argc, char const *argv[])
{fun01();return 0;
}

示例2:调用其指向的函数

#include <stdio.h>
void test01()
{printf("test01被调用了!\n");
}void fun02()
{/*函数指针的书写方式返回值类型 (*指针变量名)(形参列表)*///p1 == test01//调用函数:test01(实参列表);void (*p1)() = test01; p1();       //test01被调用了!
}int main(int argc, char const *argv[])
{fun02();return 0;
}

示例3:指向的函数的形参列表的数据类型可以忽略不写

void add(int a, int b)
{printf("sum = %d\n", a+b);
}void fun03()
{void (*p1)(int, int) = add;p1(10, 20);     //sum = 30
}

示例4:

int sub(int a, int b)
{return a-b;
}void fun04()
{int (*p1)(int, int) = sub;int num = p1(10,3);printf("num = %d\n", num);  //num = 7
}

5.2 指针变量作为函数的参数 (传递指针变量的地址 )

指针变量是一个变量,故可以作为 函数的形参,此时传递的是指针变量的地址

示例:

  • 指针变量作为形参在函数中定
  • 指针变量作为实参,在调用函数时传递
//指针变量作为形参在函数中定义
void setNum(int *num, int i)
{num[i] = 10;
}void fun05()
{int ns[5] = {0};// int *p = ns;//指针变量作为实参,在调用函数时传递//本次传递的是指针变量的地址setNum(ns, 0);printf("ns[0] = %d\n", ns[0]);      //ns[0] = 10
}

5.3 字符串指针作为实参

字符串指针作为实参,将指针指向常量区的内容传递函数。函数内部修改指针内容时,不会影响函数外部的值

示例1:函数内部修改指针内容时,不会影响函数外部的值

void setStr(char *str)
{str = "world";
}void fun06()
{char *s = "hello";setStr(s);printf("s=%s\n", s);     //s=hello
}

在这里插入图片描述

示例2:

void setchar(char *str, int i)
{str[0] = 'H';
}void fun07()
{//字符数组是指针常量,可改值不可该地址char str[] = "hello";char *p = str;//setchar函数修改的是地址中的值,所以传入该指针会出现段错误// char *p = "hello";  //常量指针,可改地址不可改值setchar(p, 0);printf("str=%s\n", str);    //str=Hello
}

5.4 字符串指针的指针作为函数参数

字符指针的指针作为函数的实参,函数的形参使用 **q(指针的指针),函数 内部修改字符指针地址,就可以 修改 函数外部的结果

示例:函数内部修改字符指针地址,就可以 修改 函数外部的结果

void setName(char **name)
{*name = "李四";
}
void fun09()
{char *n = "张三";char **p = &n;setName(p);printf("n=%s\n",n);
}

打印出对应的地址:

void setName(char **name)
{printf("name---->%p\n", name);      //name---->0x7ffd94285208*name = "李四";printf("*name改变后---->%p\n", *name);    //*name改变后---->0x400a53
}
void fun09()
{char *n = "张三"; printf("n---->%p\n", n); //n---->0x400a71printf("*n---->%p\n", &n); //*n---->0x7ffd94285208char **p = &n;printf("p---->%p\n", p); //p---->0x7ffd94285208printf("*p---->%p\n", *p); //*p---->0x400a71setName(p); printf("n修改后---->%p\n", n); //n修改后---->0x400a53printf("*p修改后---->%p\n", *p); //*p修改后---->0x400a53printf("n=%s\n",n);		//n=李四
}

图示:

在这里插入图片描述

5.5 指针作为返回值

函数中局部指针变量做为函数的返回值函数执行完毕后,其局部指针变量指向的地址也将被释放,外部无法使用,导致段错误

如需外部使用可以将 局部指针变量修改为 静态局部指针变量

示例:

int* my01()
{/*静态局部变量生命周期:随着所在函数第一次调用而生成,随着所在进程的执行完毕而销毁*/ static int num[5] = {1,2,3,4,5};return num;
}void fun11()
{int *ns = my01();printf("%d\n",ns[0]);   //1
}

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

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

相关文章

深度学习——第1章 深度学习的概念及神经网络的工作原理

1.1 序言——探索智能机器 千百年来&#xff0c;人类试图了解智能的机制&#xff0c;并将它复制到思维机器上。 人类从不满足于让机械或电子设备帮助做一些简单的任务&#xff0c;例如使用滑轮吊起沉重的岩石&#xff0c;使用计算器做算术。 人类希望计算机能够自动化执行更…

医美店会员管理系统预约小程序作用是什么

医美在美业中占据着一定地位&#xff0c;爱美使然和经济独立、悦己消费下&#xff0c;不少女性会前往医美机构做脸部整容、嫩肤补水等服务&#xff0c;如美容院一样都是具备本地外地属性的&#xff0c;因此在如今互联网盛行下&#xff0c;商家需要借势线上破解难题及增强生意效…

【预测工具】不须编码的预测和数据可视化工具

有一天&#xff0c;我的同事问我&#xff0c;他应该如何做一个快速预测模型而不是Excel&#xff0c;并产生比线性回归或Excel图中的那些简单方程更好的结果。这是我的答案。 TableCurve 2D (Image by author) Sigmaplot很早以前就推出了这个软件。它已被广泛用于在数据中寻找最…

Structured Streaming: Apache Spark的流处理引擎

欢迎来到我们的技术博客&#xff01;今天&#xff0c;我们要探讨的主题是Apache Spark的一个核心组件——Structured Streaming。作为一个可扩展且容错的流处理引擎&#xff0c;Structured Streaming使得处理实时数据流变得更加高效和简便。 什么是Structured Streaming&#…

【java+vue+微信小程序项目】从零开始搭建——健身房管理平台(2)后端跨域、登录模块、springboot分层架构、IDEA修改快捷键、vue代码风格

项目笔记为项目总结笔记,若有错误欢迎指出哟~ 【项目专栏】 【java+vue+微信小程序项目】从零开始搭建——健身房管理平台(1)spring boot项目搭建、vue项目搭建、微信小程序项目搭建 【java+vue+微信小程序项目】从零开始搭建——健身房管理平台(2)后端跨域、登录模块、sp…

python 图书馆选座小程序源码

开发工具&#xff1a; PyCharm&#xff0c;mysql5.7&#xff0c;微信开发者工具 技术说明&#xff1a; python django html 小程序 功能介绍&#xff1a; 用户端&#xff1a; 登录注册&#xff08;含授权登录&#xff09; 首页显示搜索房间&#xff0c;轮播图&#xff0…

wordpress安装之Linux解压缩安装

本次教程是为了让大家少走弯路&#xff0c;可以更直观的去认识我们不懂的知识面。 首先我们安装解压缩的软件 命令如下&#xff1a; yum install -y unzip 上一篇我们讲到传输文件了 这篇我们把传输过来的压缩包解压并进行安装。follow me&#xff01; 我们输入命令 unzi…

FDM3D打印系列——天秤座黄金圣斗士模型制作全过程视频

FDM打印天秤座黄金圣斗士全过程视频 大家好&#xff0c;我是阿赵。   这次带来的是天秤座黄金圣斗士模型的3D打印加后期加工的全过程。其实打印的过程之前都已经介绍过了&#xff0c;不过有朋友说想实际看看整个制作过程是怎样&#xff0c;所以我录了这个视频。   上完色之…

测试Centos上用Gunicorn启动的Django-Web服务在Django源文件有改变的情况下能否自动重载最新源码下的web服务

01-先上传最新的源码文件 参考博文 https://blog.csdn.net/wenhao_ir/article/details/134762966 进行 02-先在Django直接开web服务下修改源码测试 这是没有问题的&#xff0c;会自己重置。 03-开启gunicorn服务 cd /djangoproject/mmdj01/ gunicorn -c /djangoproject/mm…

【开源】前后端分离的在线考试系统,支持多种部署方式

在线考试系统 https://download.csdn.net/download/mo3408/88593116 在线考试系统是一种利用网络技术&#xff0c;实现在线出题、答题、阅卷、成绩查询等一系列考试活动的系统。它不受地理位置限制&#xff0c;可以实现远程考试&#xff0c;大大提高了考试的效率和便利性。此…

Spring MVC学习随笔-控制器(Controller)开发详解:接受客户端(Client)请求参数

学习视频&#xff1a;孙哥说SpringMVC&#xff1a;结合Thymeleaf&#xff0c;重塑你的MVC世界&#xff01;&#xff5c;前所未有的Web开发探索之旅 第三章、SpringMVC控制器开发详解 3.1 核心要点 &#x1f4a1; 1. 接受客户端&#xff08;client&#xff09;请求参数[讲解] 2…

Docker的数据持久化;Docker网络;Dockerfile编写

Docker的数据持久化&#xff1b;Docker网络&#xff1b;Dockerfile编写&#xff1b; 文章目录 Docker的数据持久化&#xff1b;Docker网络&#xff1b;Dockerfile编写&#xff1b;**Docker的数据持久化**1&#xff09;将本地目录映射到容器里2&#xff09;数据卷3&#xff09;将…

ARM架构安装RabbitMQ

1.查看centos内核版本 uname -a uname -r2.安装之前的准备工作 安装RabbitMQ必装Erlang(RabbitMQ官网添加链接描述) 2.1.Erlang简介 Erlang是一种通用的面向并发的编程语言&#xff0c;它由瑞典电信设备制造商爱立信所辖的CS-Lab开发&#xff0c;目的是创造一种可以应对…

Qt将打印信息输出到文件

将打印信息&#xff08;qDebug、qInfo、qWarning、qCritial等&#xff09;输出到指定文件来以实现简单的日志功能。 #include "mainwindow.h" #include <QApplication> #include <QLoggingCategory> #include <QMutex> #include <QDateTime>…

【Pytorch】Visualization of Feature Maps(4)——Saliency Maps

学习参考来自 Saliency Maps的原理与简单实现(使用Pytorch实现)https://github.com/wmn7/ML_Practice/tree/master/2019_07_08/Saliency%20Maps Saliency Maps 原理 《Deep Inside Convolutional Networks: Visualising Image Classification Models and Saliency Maps》&…

vue权限管理解决方案

一. 什么是权限管理 权限控制是确保用户只能访问其被授权的资源和执行其被授权的操作的重要方面。而前端权限归根结底是请求的发起权&#xff0c;请求的发起可能有下面两种形式触发 页面加载触发页面上的按钮点击触发 总体而言&#xff0c;权限控制可以从前端路由和视图两个…

深度学习记录--广播(Broadcasting)

什么是广播&#xff1f; 广播(Broadcasting)&#xff0c;在python中是一种矩阵初等运算的手段&#xff0c;用于将一个常数扩展成一个矩阵&#xff0c;使得运算可行 广播的作用 比如&#xff1a; 一个1*n的矩阵要和常数b相加&#xff0c;广播使得常数b扩展成一个1*n的矩阵 …

zemax之初级像差理论与像差校正——慧差

通过上节介绍&#xff0c;我们已经知道在轴上视场产生的球差是旋转对称的像差。在进行光学系统设计时&#xff0c;同时需要保证轴上物点和轴外物点的成像质量。轴外物点成像时会引入轴外像差&#xff0c;即轴外视场产生的慧差&#xff08;coma aberration&#xff09; 1.慧差概…

申请Azure学生订阅——人工验证

一&#xff1a;联系客服进行人工验证 点击 Services Hub 填写资料申请人工验证 点击 Azure - Sign up 进行学生验证 二&#xff1a;与客服的邮件沟通的记录 ​​​​一、结果&#xff08;输入客服给的验证码后&#xff0c;笔者便得到了学生订阅&#xff09;&#xff1a; 二…

k8s中批量处理Pod应用的Job和CronJob控制器、处理守护型pod的DaemonSet控制器介绍

目录 一.Job控制器 1.简介 2.Jobs较完整解释 3.示例演示 4.注意&#xff1a;如上例的话&#xff0c;执行“kubectl delete -f myJob.yaml”就可以将job删掉 二.CronJob&#xff08;简写为cj&#xff09; 1.简介 2.CronJob较完整解释 3.案例演示 4.如上例的话&#xf…