本章要点
1.变量、内存单元和地址的关系。
2.如何去定义一个指针,怎么使用指针变量。
3.指针变量的初始化。
4.指针的基本运算以及怎么使用指针所指向的变量。
5.指针作为函数的参数有什么作用。
6.指针、数组和地址间的关系。
7.对于字符串的一些处理函数以及字符指针。
8.用指针实现动态内存分配。
【重磅】以上是每一块主要内容,也会穿插一些扩展和个人理解。
一.变量、内存单元和地址的关系。
【回顾】我们之前学过变量有局部变量、静态变量和全局变量,局部变量是在定义时系统分配相应的存储空间,函数调用结束后空间被系统回收。静态变量的初始化仅起到一次作用,每次使用它都是用上次使用时的值。全局变量一般定义在函数外且开头位置,任何函数可使用。
系统会根据变量的数据类型分配相应的内存单元,int型2字节,char型1字节,double型8字节,float型4字节。
字节大小就相当于房间大小,而房间号就是地址,指针变量存储的就是地址。
总的来说,变量就是房间主人,内存单元是房间大小,地址是房间号。
二.如何去定义一个指针,怎么使用指针变量。
定义指针跟定义一个变量形式基本一样,具体格式如下。
void *p;
上面是定义了一个通用指针,其中 * 是指针声明符,就是说明一下p是一个指针变量。当然定义指针视情况而定,void可改成你想定义的类型,但必须与指向的变量类型一致。比如想指向一个int型的变量a,就定义为如下。
int *p=&a
三.指针变量的初始化。
之前学的定义一个变量,要初始化才能使用,指针也是如此,但是指针的初始化不能是随意的数值,可以是0;或者用一个地址,如&a等等去给指针初始化,其实就相当于赋值。
int *p=NULL;
int *p=0;
NULL表示空操作,对应ASCII是十进制的0,故上述两条语句意义一样。
四.指针的基本运算以及怎么使用指针所指向的变量。
指针的运算有大致两种,一是指针与指针,二是通过指针间接运算指针所指向的变量。
第一种:指针可以给指针赋值,那么这两个指针共同指向相同的地址或变量,比如
int *p,*q,a=100;
p=&a;
q=p;
上述程序意思是指针p指向a所在的地址,即指向变量a,指针p的值是a的地址值,就是房间号,然后把p的值赋给q,q的值也是a的房间号,这样p和q共同访问a,都去a房间串门子了。
但是指针只能给一个其他指针赋值。(知道这么回事就行)
所以指针p,q的值是地址,而*p和*q的值是变量a的值,他仨相同,因此改变任意一个的值,其他两个都跟着变,除非p和q的值改变(p和q值改变即他们访问的地址改变。就不再访问a了)。比如以下程序段:
int *p,a=1;
p=&a;
a=*p++;
//* 这里*p++等价于*(p++),先赋值再自加,最后p的值加1,
那么指针p访问的地址改变,就不再访问a所在地址了。 *//
第二种:通过指针间接运算指针所指向的变量,就是用*p等等去运算,这是前面的 * 叫做间接访问地址符。
五.指针作为函数的参数有什么作用。
之前我们所学的函数,返回值只能有一个,若想返回多个值,就用到了指针,指针作为函数的参数,可以返回多个值(其实并不是通过return实现,效果一样罢了)。如以下程序段想交换a和b的值。
void exchange(int *p,int*q)
{
int m;
m=*q;
*q=*p;
*p=m;
}
六.指针、数组和地址间的关系。
当定义一个数组时,系统会给数组分配一个地址,叫做数组的基地址,基地址就是数组第一个元素的地址,用数组名表示,然后连续存储数组的元素。比如数组a【10】,&a【0】和a的值一样,都是基地址的值。
而之后通过指针去使用数组其他元素就通过改变指针的值,这里先说p++的含义,p++并不是说指针值加1,这里以数组为例,p++加完实际上是跳到了下一个元素所在地址,如果刚开始p=3000,然后数组是char型,p++后p=3001;如果是double型,p++后p=3008,这取决与每个数据所占的字节数。这里也涉及一些运算,以数组为例,如果p和q分别指向数组不同的元素,那么p-q是他俩之间的元素个数,(int)p-(int)q则是之间数据所占的字节数。
七.对于字符串的一些处理函数以及字符指针。
函数方面有输入输出以及字符串之间操作的一些函数。
1.字符串输入输出。
输入:gets(line),输入的字符串存到line数组中,并且系统将输入的字符串和字符串终止符\0存入数组line中。
scanf("%s",line);输入字符串时格式控制说明用%s,并且无论scanf还是gets后面的输入参数必须是字符型数组名。
输出:puts(输出参数),将line数组中的字符串输出,遇到\0停止。
printf(“%s”,输出参数);输出字符串时格式控制说明用%s,puts和printf输出时后面的输出参数可以是数组名或字符串常量。
2.字符串之前操作的函数。(一下函数的调用必须用头文件#include
1)字符串复制:
strcpy (s1,s2)
//*s1必须是字符型数组基地址,s2可以是字符数组名或字符串常量*//
2)字符串连接:
strcat(s1,s2)
//*s1必须是字符数组基地址,s2可以是字符数组名或字符串常量*//
把s2里的字符串连接到s1后面,比如s1里存了“happy”,以\0结尾,连接时取代\0往后连接,然后再以\0结尾,前提必须保证s1有足够空间去连接s2。
3)字符串比较:
strcmp(s1,s2)
//*s1、s2可以是字符数组名或字符串常量*//
字符串比较大小实际上是从第一个字符开始,比较他们的ASCII码,做差,这样依次进行比较,返回值为正数、0或负数。
4)字符串长度:
strlen(s1)
//*s1可以是字符数组名或字符串常量*//
该函数返回值是数组s1中\0之前的字符个数。
八.用指针实现动态内存分配。
这里只说主要用的两个函数,其他可以百度。这些函数需要使用头文件#include
1.动态内存分配函数malloc()
基本格式:
void *malloc(n*sizeof(int))
eg调用:
int *p=(int *)malloc(10*sizeof(int));
//*意思是分配连续的10int型数据大小的存储空间,并且把首地址赋值给指针p*//
2.动态存储释放函数free()
基本格式(以定义好的指针p为例):
free(p)
与malloc函数一起用,通过malloc向系统借了空间,通过free还回去,注意:free括号里的指针值必须是想系统借的时候系统给你赋的那个值,不能是别的,否则出错。
总之,有借有还。