首页 > 其他分享 >指针

指针

时间:2022-12-25 18:00:44浏览次数:22  
标签:变量 int 地址 数组 指针 函数

指针

变量的地址

内存每一个字节都有一个对应的地址编号,方便计算机快速找到对应内存空间。也可以将地址形象的称为指针

假如:

int a=6; 系统分配10002~10005地址空间给a,存储int类型的数值6,并且生成变量a和地址10002的对照表。在执行代码时,通过变量名找到对应的地址,然后通过数据类型int获取4个字节空间内的信息,读取对应的数值

scanf(“%d”, &a); &获取对应a变量的地址,将键盘输入的指存入到对应地址内存中

指针变量

如果将一个变量b用来存储另一个变量a的地址(指针),称变量b为指针变量

int a;

int *b;

变量a的地址为10001,地址10001的内容为int类型数据10;

变量b的地址为10007,地址10007的内容为指针类型数据10001

定义指针变量

类型名 *指针变量名
  • 类型名表示指针变量用来指定对应变量的数据类型。让系统知道对应地址的数据在内存中占的字节数和存放方式

  • *表示变量时一个指针类型的变量

  • 指针变量只能存放指针,不能直接将一个数值赋值给指针变量。 int *p = &a;

在定义指针变量时,可以同时该指针变量初始化

引用指针变量

&:取地址运算符。例如&a获取变量a的地址

*:指针运算符。例如*p表示指针变量p指向的对象,与定义时不同

函数传递指针变量

也可以在函数的参数传递过程中传递指针变量

指针和数组

数组元素的指针

变量有地址,同样的数组元素也有地址,也可以通过指针指向数组元素

数组名代表数组中第一个元素的地址。并不是代表整个数组

数组元素的指针运算

当指针指向数组元素时,可以对指针进行加减运算

  • p+1: 指向同一个数组中的下一个元素地址,不是地址数值+1,根据定义的类型大小增加(++)
  • p -1: 指向同一个数组中的上一个元素地址,不是地址数值 -1 ,根据定义的类型大小减小(--)
  • 如果p = &a[0], p+3 是a[3]的地址,也等效于a+3
  • *(p+3)获取p+3地址的数组元素。[ ]实际是变址运算符,a[i]等效为*(a+i)
  • 如果p1和p2指向同一个数组中的元素,则p1-p2的结果为之间的元素个数

指针引用数组元素

通过指针的方法引用数组元素的方法:

  • 下标法 例如:a[i]
  • 指针法 例如:(a+i)或(p+i),其中a是数组名,p是指向数组元素的指针变量

注意:

  • a是数组首元素的地址,是一个常量,不能通过a++等方式改变a的值
  • 当指针p指向数组元素时,指针p可以使用p[i]带下标的方式。当p = a时,p[i]等同于a[i].当p = &a[2],p[i] = a[i+2]

函数传递指针

在之前的函数参数为数组这一节强调,函数如果传递数组名时,传递的是数组首地址,且如果形参数组中各元素的值发生变化,则实参数组元素的值也跟着改变

  • 形参经过编译后,自动编译为一个指针变量a,因此形参的定义[ ]中括号中可以是任意数值

  • 函数传递数组一共有4中情况:

    • 形参和实参都用数组名
    • 实参数组名,形参指针名
    • 实参指针名,形参数组名
    • 形参和实参都用指针名

指针引用多维数组

现有一个二维数组:int a[3][4] = {{3,8,6,2},{5,6,3,9},{2,5,3,0}}(a包含3行,分别用a[0],a[1],a[2]表示)

二维数组地址说明:

  • a代表二位数组首行的起始地址1244952

  • a+1代表序号为1的行的地址1244968

    计算方法:1244952+4*4 = 1244968

  • a[0],a[1],a[2]是一维数组名,也是各行的首地址

    a[0] = &a[0][0] = *(a+0)

    a[1] = &a[1][0] = *(a+1)

    a[2] = &a[2][0] = *(a+2)

  • a[0]是一维数组名,则a[0]+1 表示 a[0][1]的地址

    a[1] + 2 表示a[1][2]的地址,即&a[1][2]

    a[1]+2 = *(a+1) +2 = &a[1][2]

  • a[0][2] = *(a[0]+2) = ((a+0) +2)

    a[1][2] = *(a[1]+2) = ((a+1) +2)

注意: a+1 和a[1]的结果一样,但是性质不同。a+1指向第2行(属性为行),a[1]指向第2行首元素地址(属性为元素),因为C语言的地址信息中即包含了位置信息,也包含了数据的类型信息

例如:a+1再加1,是下一行,而a[1]+1是下一个元素

指针和字符串

指针指向字符串常量

引用字符串的方法

  • 字符数组存储字符串
  • 字符指针变量指向字符串常量

注意:

  • %s是通过字符指针找到字符串常量的首地址,使地址不断加1,直到遇到\0为止,输出地址对应内容
  • 对数值型数组是不能通过%s一次性输出全部元素,只能元素逐个输出

函数传递字符指针

在函数传递过程中,可以使用字符数组名作参数,也可以使用字符指针变量作参数

字符数组和字符指针的对比

通过以上的例子,可以看到字符数组和字符指针变量都能实现对字符串的操作

它们之间的区别:

  • 字符数组包含多个元素,每个元素都有自己的地址,而字符指针变量中存放的是地址
  • 可以对字符指针变量赋一个地址,但不能对字符数组名赋值,它是一个常量
  • 字符数组除了在初始化是可以一次性对所有元素赋值,非初始化部分不能一次性赋值,但字符指针变量可以实现
  • 字符指针变量一旦定义,需要及时对它赋予一个地址。否则会出现指针地址不明确,导致破会系统
  • 字符数组的元素值可以被改变,但字符指针指向的字符串常量中的元素不能被改变

补:使用字符指针变量指向的字符串或字符数组都可以实现printf函数的可变格式输出。

函数指针变量

函数指针

什么是函数指针?

程序代码中的函数在编译时,会分配一段存储空间存储函数可执行代码,函数名代表函数的起始地址。调用该函数时,会从函数名处找到函数的起始地址,并执行对应函数

函数名即是函数指针

定义一个指针变量用于指向函数,存放函数的起始地址,则此指针为函数指针变量

定义函数指针变量

 类型名 (*指针变量名)(函数参数列表)

注意:

  • 定义函数指针变量之前需要确定好类型名,类型名代表可以指向的函数类型

    例如:int ( *p )(int ,int)代表指针p只能指向int类型的函数,且对应的函数有两个整型形参

  • *指针变量名 需要用括号括起来

  • 给函数指针变量赋值时,只需给出函数名, 不用写入参数

  • (*指针名)是调用函数,使用(*指针名)替代函数名即可

  • 函数指针变量没有加减运算,是无意义的运算

函数指针变量对比函数名的两者使用的优点:函数名调用函数,只能调用指定的一个函数,而函数指针变量可以通过改变指针变量的地址灵活调用不同的函数

函数指针做函数参数

在实际使用中,常常将函数指针作为另一个函数的参数,传递到其他函数中

例如函数指针变量p指向函数a,函数b中的一个参数为变量p

int b( int ( *p ))

函数返回指针

函数除了可以返回整型、字符、浮点数等以外,还可以返回指针

返回指针的函数定义方式:

类型名 *函数名 (参数列表)

例如:

int *ff(int a, int b)

返回指针的方法:通过return函数返回指针变量名

指针数组

什么是指针数组

一个数组,每个元素都是指针型数据,称为指针数组

定义方法:

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

使用场景:当有多个字符串时,可以使用指针数组处理更加灵活

多重指针

一个指针变量指向另一个指针称为多重指针

定义多重指针的方法:

指针类型 **指针名   

例如:

char  **p

理论上可以出现3重地址,甚至更多重地址,但是通常间接访问变量一般不会超过二级地址。级数越多越难于理解和使用

main函数的参数

main函数是程序的起始位置,一般写成void main( ),其中括号里面是没有任何参数,本质上main函数可以给定参数。有参数的形式为:

void main(int argc, char *argv[ ] )   

其中argc和argv就是main函数的形参。argc接收参数个数,argv是字符指针数组

由谁传递实参给main函数?

由操作系统传递实参给main函数。实参是和执行文件的命令一起给出的

如何传递实参给main函数?

  1. visual c++菜单栏project—settings—Debug—program arguments

  2. 在DOS、Linux终端、Macos终端中命令行的一般形式为:

    命令名 参数1 参数2 … 参数n
    

其中命令名为可执行文件名(包含main函数的.exe文件),各个参数之间用空格分隔

动态内存操作

内存存储区分为静态存储区和动态存储区,全局变量以及静态局部变量是分配的静态存储区,而局部变量(非静态)是分配动态存储区。动态分配的空间使用时随时开辟,不需要时随时释放。也可以通过代码来分配动态内存

malloc

开辟动态存储区

malloc(size)

例如:

int *p
p = malloc(7*4)

开辟一个长度为size(字节)的连续空间,size为正整数,函数返回分配空间的首地址,malloc函数为指针型函数。如果此函数没有成功分配空间(例如空间不足、空间异常等),则返回空指针(NULL)

calloc

开辟动态存储区

calloc(unsigned n, unsigned size)

例如:

p = calloc(50,4)

开辟一个n*size长度的空间,空间分配较大

realloc

为已开辟的空间重新分配动态存储区

realloc(p, size)

例如:

p = realloc(p,10)

p为之前已开辟过的动态存储空间,通过realloc可以改变p的空间大小,改为size大小

free

释放已经开辟的内存空间

free(p)

例如:

free(p)

p为之前已开辟过的动态存储空间,通过free可以将p指向的内存空间释放,让系统回收

动态内存操作函数包含在stdlib.h头文件中,因此在使用malloc、calloc、realloc、free函数之前需要在文件开头加上#include<stdlib.h>

标签:变量,int,地址,数组,指针,函数
From: https://www.cnblogs.com/ruoxianshi/p/17004321.html

相关文章

  • 关于结构体和指针
    typedefstructStu{charname[20];shortage;chartele[12];charsex[5];}Stu;voidPrint(Stu*ps){printf("name:%s\n",ps->name);printf("age:%d\n",(*ps).a......
  • 野指针
     malloc/free野指针:不是NULL指针,是指向“垃圾”内存的指针。“野指针”是很危险的。 出现“野指针”主要有以下原因:指针变量没有被初始化。指针p被free或者delete......
  • Go 快速入门指南 - 变长参数和指针参数
    变长参数在函数的最后一个参数的数据类型之前加上省略号 ​​...​​​ ,表示该参数的数据类型是 ​​变长类型​​​,调用该函数时可以传递任意数量 ​​(0-N)​​......
  • 指向分析/指针分析(Pointer analysis)
    在基于SAST的静态分析工具中,指向分析是经常采用的分析技术。指向分析怎么理解呢?指向分析是一种用于分析指针和内存引用所指向的变量或内存地址的静态代码分析技术。指向分析......
  • xxl-job使用openfeign,报空指针异常(java.lang.NullPointerException)
    当使用xxl-job调用项目时,如果刚好使用了feign中间件调用微服务接口,会报空指针异常可以在代码前面加一句:RequestContextHolder.setRequestAttributes(newServletReques......
  • 反射 指针 字符串
     func largestMerge(s, t string) string {    n := len(s)    sa := *(*[]int32)(unsafe.Pointer(reflect.ValueOf(suffixarray.New([]byte(s + ......
  • Go 快速入门指南 - 变长参数和指针参数
    变长参数在函数的最后一个参数的数据类型之前加上省略号 ... ,表示该参数的数据类型是 变长类型,调用该函数时可以传递任意数量 (0-N) 的该类型的参数。一个函数......
  • String.contains空指针异常
    今天在写业务代码的时候,大致如下   然后a.contains报了空指针异常,让我很是诧异结果发现,是缓存获取到了一个nullnull.contains这种样子就会出现空指针......
  • 使用指针来完成三个数由大到小输出(简单指针的应用)
    #include<stdio.h>intmain(){voidexchange(int*r1,int*r2,int*r3);inta,b,c,*p1,*p2,*p3;scanf("%d%d%d",&a,&b,&c);p1=&a;p2=&b;p3=&c;//若在数组中p1中......
  • Go语言基础之指针
    区别于C/C++中的指针,Go语言中的指针不能进行偏移和运算,是安全指针。要搞明白Go语言中的指针需要先知道3个概念:指针地址、指针类型和指针取值。Go语言中的指针......