c语言-指针
指针是什么:
- 地址:
- 位置信息
- 类型信息
区别:存储单元的内容
对变量的访问都是通过地址进行
指针变量是什么:
- 存放地址的变量
指针变量作为函数参数
注意:
- c语言中实参变量和形参变量之间的数据传递是单向传递的“值传递”
- 而指针作为函数参数时,同样要遵循“单向值传递的规则`!
指针指向数组:
指针运算
如: int a[10]; int *p = a;
指针法 ==> 下标法
- p ==> &a[0]
- p+1 ==> &a[1]
- *p ===> a[0]
- *(p+1) ===> a[1]
- p2-p1 ===> 2
1 |
|
注意:两个地址不能相加,如p1+p2没有意义
引用数组元素的三种方法
- 1.下标法
a[i]
- 2.通过数组名计算数组元素的地址,找出元素的值
{1.2.效率相同,都是转化为*(a+i)}
- 3.使用指针变量指向数组元素
(效率最高,不必每次都重新计算地址)
注意:
- 不能将数组名a++,因为本质上:数组名是一个常量地址,不可以改变;
- 而指针变量可以进行运算,因为它是一个变量`
数组的高级用法:
- p[i]是什么
1 |
|
- 指针引用数组元素方法总结
1 |
|
使用数组名作为函数参数
通过指针引用多维数组
1.多维数组元素的地址
1 |
|
1 |
|
tips:在二维数组a[3][4]中
a[0] 类型为int*型(指向整型变量
a 类型为int (*p)[4] (指向含有4个元素的一维数组)
2.指向多为数组元素的指针变量
利用二维数组的顺序存储方式 a[i][j] ===> a + (i*m +j) ===》基类型: int*
利用指向包含m个元素的一维数组 int (*p)[m] ===>基类型:一维数组
3.指向数组的指针作为函数参数
- 1.用指向变量的指针变量
- 2.用指向一维数组的指针变量
1 |
|
通过指针引用字符串
字符串的引用方式:
- 数组名+下标
- 用字符指针变量指向一个字符串常量
1 |
|
字符指针作函数参数
使用字符指针变量和字符数组的比较
tips:字符串是常量,
在C语言中没有专门的字符串变量,如果想将一个字符串存放在变量中以便保存,必须使用字符数组,即用一个字符型数组来存放一个字符串,数组中每一个元素存放一个字符。例如“char a[10]=”love”.”
- 字符数组由若干个元素组成每个元素放一个字符;
- 字符指针变量存放的是地址
2.赋值方式不同:
- 可以对字符指针变量赋值
- 不可以对数组名赋值
3.初始化的不同:
字符数组:
- 字符数组仅仅可以在定义!时可以整体赋值
- 之后不能使用赋值语句对全部元素进行赋值
字符指针变量:
- 可以先定义字符指针,然后再给字符指针整体赋值
- 4.存储单元的内容:
- 字符数组:预先定义大小
- 字符指针:分配一个指针变量的大小
16位机器的代码时,指针占2个字节
32位机器的代码时,指针占4个字节
64位机器的代码时,指针占8个字节
- 指针变量的值可以改变
- 字符数组名代表一个固定的值,不能改变
- 字符数组的值是可以改变的(可以再进行赋值)
- 字符指针变量指向的字符串常量中的内容是不可以被取代在(不能再进行赋值)
1 |
|
1 |
|
7.引用数组:
- 字符数组:
- 下标法(数组名 or 下标)
- 地址法
- 指针变量指向数组:
char *a = "china";
- 可以用a[5]获取相应的值
- 字符数组:
- 用指针变量指向一个格式字符串,可以用其代替printf中的格式字符串
1 |
|
1 |
|
指向函数的指针
什么是函数指针:
- 函数名代表函数的起始地址
1 |
|
1 |
|
赋值:
- 指向函数的指针只能指向
在定义时
指向的类型的函数 - 只需要给出函数名,
不能给出函数参数
- 指向函数的指针只能指向
1 |
|
调用:
- c = (*p)(a,b);
- c = p(a,b);
- 注意返回值c的类型
- 对函数的指针变量不能进行算术运算,没有意义
- 通过指针变量可以先后调用不同的函数
1 |
|
用指向函数的指针作为函数参数:
- 把函数的入口地址作为参数传递到其他函数
1 |
|
返回指针值的函数
- 返回值的类型是指针类型
- 类型名 * 函数名(参数列表)
指针数组和多重指针
指针数组:
一个数组–里面的元素为指针类型数据
一般用来装多个字符串
1
2int *p[4];
//*比[]优先级低
实例:利用指针数组实现字符串排序
1 |
|
1 |
|
注意点:
不能写成以下形式:
if ( * name[ k]> * name[j] ) k= j ;
这样只比较name [ k ] 和name [ j] 所指向的宇符串中的笫1 个宇符。
- 字符串比较应当用strcmp 函数。
- 想想一下如果字符串的第一个字符都相同,那么会发生什么。
tips:
1 |
|
指向指针数据的指针变量
- 指向指针的指针
1 |
|
实例1:char**p ---> char *name[]
1 |
|
实例2:int **p --> int *num[]
1 |
|
指针数组作为main函数的形参
1 |
|
argc (argument count 的缩写,意思是参数个数)
argv(argument vector 缩写,意思是参数向量)
如果用带参数的main 函数,其笫一个形参必须是int 型,用来接收形参个数.
第二个形参必须是宇符指针数组,用来接收从操作系统命令行传来的字符串中首字符的地址。
什么情况会用到这个?
例如在DOS, UNIX 或Linux 等系统的操作命令状态下,在命令行中包括了命令名和需要传给ma in 函数的参数。
命令行的一般形式为:
命令名参数1 参数2…参数n
动态内存分配与指向它的指针
- 动态分配区域
- 堆区(heap)
- 静态存储区域:
- 栈区(stack)
怎样动态分配内存:
malloc、calloc、free、realloc函数
1.malloc函数
1 |
|
size:开辟连续空间,大小为size字节
返回值:如果此函数未能成功地执行(例如内存空间不足), 则返回空指针(NU LL ) 。
1 |
|
2.calloc函数-动态数组
1 |
|
nitems − 分配一维数组元素个数
size − 每个元素个数的大小
1 |
|
3.realloc函数 – 重新分配动态存储区
1 |
|
如果已经通过matloc 函数或ca lloc 函数获得了动态空间,想改变其大小,可以用recalloc 函数重新分配。
ptr - 这是指向先前用 malloc、calloc 或 realloc 分配的内存块的指针,将被重新分配。如果该指针为 NULL,函数将分配一个新的内存块并返回一个指向该内存块的指针。
size - 这是内存块的新大小,以字节为单位。如果它为 0 且 ptr 指向一个现有的内存块,ptr 指向的内存块将被解分配,并返回一个 NULL 指针。
1 |
|
4.free函数–释放动态内存
1 |
|
- ptr - 这是指向先前用 malloc、calloc 或 realloc 分配的内存块的指针,将被取消分配。如果参数传递的是空指针,则不会执行任何操作。
1 |
|
void指针类型: - 指向空类型
或不指向确定的类型
的数据
注意! 不要把”指向void 类型“理解为能指向“ 任何的类型”的数据
1 |
|
void指针存在的意义:
当使用动态内存分配函数时,我们其实
只希望获得其动态存储区的起始地址
在c89中
malloc函数的返回地址一律指向字符型数据,即得到char* 型指针)
原型为:
1
char * malloc( unsigned int size)
C99对此作了修改
这些函数不是返回char *指针,而是使其
无指向
,函数返回void * 指针。这种指针称为空类型指针(typeless pointer)
,它不指向任一种具体的类型数据,只提供一个纯地址。- 不能通过void * 指针存取数据,在程序中它只是
过渡性
的 - 只有转换为有指向的地址,才能存取数据
- 不能通过void * 指针存取数据,在程序中它只是
自动进行类型转换
1
2
3
4
5int *pt;
//手动
pt = (int*)malloc(100);
//自动
pt = malloc(100);