1.数组
p162
2.找出矩阵中的最大值(二维数组的应用)
3.指针和地址
1. 地址
地址和指针是两个重要的概念,在程序运行中,变量或者程序代码会被存储在以字节为单位组织的存储器中。在C语言中,如果定义了一个变量,在编译时就会根据该变量的类型给它分配相应大小的内存单元。
例如int类型占2个字节,需要分配2个字节的内存单元,char型变量需要分配1个字节的内存单元,float型变量和double型变量则需要分配4个字节和8个字节的内存单元。
计算机对内存单元的数据操作一般是按“地址”存取的,也就是对内存单元进行编号。
因为int型变量的存储长度为2个字节,所以C语言编译器将它们分配到的地址为1000~1001、1002~1003和1004~1005的内存单元中,而程序执行时是将变量翻译为它所在的内存地址进行操作的。
int x=20,y=1,z=155;
如调用函数printf("%d",x):将x所在的内存地址1000~1001单元的内容按照整数格式输出。这种使用变量的方法叫做“直接访问”。一般以变量所在的内存单元的第1个字节地址作为它的地址,如上述代码中变量x的内存地址为1000,y的内存地址为1002,z的内存地址为1004。而它们的内容分别为20,1,155。
2.指针
在C语言中还有一种使用变量的方法,即通过变量的地址进行操作:用指针访问内存和操纵地址。假设再定义一个变量p,它位于2000单元,该单元中存放了变量x的地址1000。此时,取出变量p的值1000,就可以访问访问内存为1000的单元,实现对变量x的操作,也就是说通过变量p,就可以间接访问变量x。
在C语言中把这种专门用来存放变量地址的变量称为“指针变量”,简称为指针。
C语言使用指针对变量的地址进行操作。指针是用来存放内存地址的变量,如果一个指针变量的值是另外一个变量的地址,那么就称指针变量指向那个变量。前面提及的p就是指针变量,它存放了变量x的指针地址,即指针变量p指向变量x。
4.指针变量的定义
如果在程序中声明一个变量并使用地址作为该变量的值,那么这个变量就是指针变量,一般形式为:
类型名 *指针变量名
这里变量 p是指向int型变量的指针。指针值可以是特殊的地址0,也可以是一个代表机器地址的正整数。
注:指针声明符 * 在定义指针变量时被使用,说明被定义的那个变量为指针
注:指针变量的类型并不是指针变量本身的类型,而是指它所指向的变量的数据类型。无论何种类型的指针变量,它们都是用来存放地址的,因此指针变量自身所占的内存大小和它所指向的变量数据类型无关,尽管不同类型的变量所占的内存空间不同,但不同类型指针变量所占内存空间大小都是相同的。
int i, *p; //定义指针变量p
p=&i; //指针p是存放变量i的地址
p=0; //空指针
p=NULL; //空指针
p=(int*)1732; //使用强制类型转换(int*)来避免编译错误,表示p指向地址为1732的int型变量
在定义指针变量时,要注意:
1.指针变量名是一个标识符,要按照C标识符的命名规则对指针变量进行命名。
2.指针变量的数据类型是它所指向的变量的类型,一般情况下一旦指针变量的类型被确定后,它只能指向同种类型的变量
3.在定义指针变量时需要使用指针声明符*,但指针声明符并不是指针的组成部分。例如定义int *p;时,说明p是指针变量,而不是*p。
5.指针的基本运算
如果指针的值是某个变量的地址,通过指针就能间接访问那个变量,这些操作由取地址运算符&和间接访问运算符 * 完成。此外,相同类型的指针还能进项赋值、比较和算术运算。
1. 取地址运算和间接访问运算
单目运算符 & 用于给出变量的地址。例如:
int *p,a=3; //p指针用来存放a的地址
p=&a; //用运算符&来读取a的地址,并将这个地址值作为指针p的值,使指针p指向变量a。
注:指针的类型和它所指的变量的类型必须相同。
在程序中,* 除了用于定义指针变量外,还被用于访问指针所指向的变量,它也称为间接访问运算符。例如,当p指向a时,* p和a访问同一个存储单元,* p的值就是a的值。* p就相当于a。
下面通过实践,对这些概念进行更深入的了解:
/*取地址运算和使用指针访问变量*/
#include<stdio.h>
int main()
{
int a=3,*p; //定义整型变量a和整型指针p
p=&a; //把变量a的地址赋值给指针p,即p指向a
printf("a=%d,*p=%d\n",a,*p); //输出变量a的值和指针p所指向的值
*p=10; //对指针p所指向的变量赋值,即对变量a赋值
printf("a=%d,*p=%d\n",a,*p); 输出改变后变量a的值和指针p所指向的值
printf("Enter a:");
scanf("%d",&a); //输入a
printf("a=%d,*p=%d\n",a,*p);
(*p)++; //将指针所指向的变量加1
printf("a=%d,*p=%d\n",a,*p);
return 0;
}
第一次出现的*p和后出现的*怕,尽管形式是相同的,但含义不相同。第一次的定义了指针变量,p是变量名,*表示的是其后变量为指针。第二次出现的*p代表p所指向的变量。
注:*p=*p+1、++*p和(*p)++,都是将指针p所指向的变量的值加1。而*p++等价于*(p++),先取*p的值作为表达式的值,再将指针p的值加1,运算后,p不再指向变量a。
#include<stdio.h>
int main()
{
int a=1,*p;
p=&a;
printf("a=%d,*p=%d\n",a,*p);
*p++;
printf("a=%d,*p=%d\n",a,*p);
return 0;
}
#include<stdio.h>
int main()
{
int a=1,*p;
p=&a;
printf("a=%d,*p=%d\n",a,*p);
(*p)++;
printf("a=%d,*p=%d\n",a,*p);
return 0;
}
观察两者,不难发现区别。
再进行深入了解:
#include<stdio.h>
int main()
{
int a=1,*p;
p=&a; //将a的地址赋值给变量p
printf("a=%d,*p=%d\n",&a,p);
*p++;
printf("a=%d,*p=%d\n",&a,p);
printf("a=%d,*p=%d\n",a,*p);
return 0;
}
由此可见,p与a的地址在*p++后已不相同,因此p不再指向变量a。
2. 赋值运算
一旦指针被定义并赋值后,就可以如同其他类型变量一样进行赋值运算,例如:
int a=3,*p1,*p2; //定义整型变量指针p1和p2
p1=&a; //使指针p1指向整型变量a
p2=p1;
printf("*p1=%d,*p2=%d",*p1,*p2);
return 0;
将变量a的地址赋给指针p1,再将p1的值赋给p2,因此指针p1和指针p2都指向变量a。此时,*p1,*p2和a访问同一个储存单元,它们的值都一样。
给指针赋值是使指针和所指向变量之间建立关联的必要过程。指针之间的相互赋值只能在相同类型的指针之间进行,可以在定义时对指针进行赋值,也可以再程序运行过程中根据需要对指针重新赋值,但要特别注意:指针只有在被赋值以后才能被正确使用。
注:只能将一个指针的值赋给另一个相同类型的指针。
好久没打卡C了,重新开始C的自学旅程!
如有错误,欢迎指出。