说明:
最近学校课程开设了《数据结构》的课程,无疑,数据结构的重要性在IT生涯的进阶路上是不可置疑的,也常说,数据结构是专业性与非专业性的分界线。所以无论以后走的是什么方向,毕竟是读计算机专业的,所以必须学好数据结构的。虽然目前我给自己定的方向是走运维/系统架构方向的,可有句话说得好,不懂开发的运维注定会被淘汰,在IT这一行,要让自己变得更加强大。最近也一直在学Python,感觉还不错,学数据结构相信对自己也肯定有好处的,对一些较为底层的知识有些了解和理解,这样才能走得更远!
无疑C语言就很重要了,而在C语言当中,数组/指针/结构体/链表等这些都是非常重要的,所以根据往前自己的学习经验,需要把C语言中的指针之后等更深入的知识好好再回顾和总结一遍,为学好数据结构打下坚实的基础吧!
一.指针变量
1.定义指针变量
·变量的指针包含两方面信息:指向变量的地址和指向存储单元的数据类型;
·定义指针变量需要指定基类型,方法如下:
int *pointer;
·基类型说明存储单元的数据类型,指针的值即是所指向变量的地址;
·注意下面的一个赋值为非法的:
*pointer = 100; ===>左右类型不一致,赋值非法
·基于内存的地址编址可知,内存的值是无符号整型;
·为指针变量赋初值时注意是否有乱指的情况(即指向程序不授权的地址,会出错),会有下面三种情况:
1.正确指向本程序的变量 ===>正确 2.指向其它程序未授权的地址 ===>非法 3.未赋初值,只有随机值,指向未知地方 ===>非法
·可看下面一个非法的示范:
#include<stdio.h> void swap(int *p1, int *p2) { int *p3; ===>定义p3指针变量时已有初值,为随机值 *p3 = *p1; ===>修改p3指向的值,会出现“未授权”的情况,即程序试图去修改一个未知地方的值 *p1 = *p2; 这显然是会引起错误的。 *p2 = *p3; }
2.引用指针变量
·两个重要的符号:
& 取地址运算符,&a取变量a的地址 * 指针运算符,*p取指针p所指向的变量的值
·常用的三种指针引用:
(1)对指针变量赋值
pointer = &a ===>把a的地址赋给指针变量,或让pointer指向a
(2)引用指针变量指向的值
printf("%d",*pointer); ===>输出a的值
(3)直接引用
printf("%d",pointer); ===>直接输出指针变量的值,是一个内存地址
3.指针变量作用之一:作函数参数
·编写一个交换两数值的程序,用指针实现,代码如下:
a.main函数代码如下:
#include<stdio.h> int main(void) { int a,b; int *p1,*p2; printf("Please input a:");scanf("%d",&a); printf("Please input b:");scanf("%d",&b); printf("a=%d, b=%d\n",a,b); p1 = &a;p2 = &b; swap(p1,p2); printf("Now, a=%d, b=%d\n",a,b); return 0; }
b.swap函数代码如下:
#include<stdio.h> void swap(int *p1, int *p2) { int temp; temp = *p1; *p1 = *p2; *p2 = temp; }
·编译,链接与执行:
[email protected]:~/stuc$ gcc -o swap swap_main.o swap_sec.o [email protected]:~/stuc$ ./swap Please input a:3 Please input b:4 a=3, b=4 Now, a=4, b=3
二.指针与数组
1.数组元素的指针
·所谓数组元素的指针就是数组元素的地址;
·数组的引用有下标法和指针法,在编译时,最终数组引用的实现都是通过指针实现的;
·数组名实际为一地址常量(指针常量),指向数组的第一个元素,该地址值不可改变;
·可以以指针的操作方式来引用数组中的元素;
2.通过指针运算引用数组元素
·只讨论加减:
p1+1:表示指向下1个元素,指针移动基类型个字节 p1-1:表示指向上1个元素,指针移动基类型个字节 p1+2:表示指向下1个元素,指针移动(基类型 * 2)个字节
·a[3]中,[ ]实际是取址运算符,等价于:*(a+3);
·通过指针运算操作,编写一个遍历数组的程序:
a.代码如下:
#include<stdio.h> int main(void) { int a[10], *p, i; for(i = 0;i < 10;i++) a[i] = i + 10; p = a; for(i = 0;i < 10; p++, i++) printf("a[%d]=%d ", i, *p); printf("\n"); return 0; }
b.执行过程:
[email protected]:~/stuc/shuzu$ gcc -c value.c [email protected]:~/stuc/shuzu$ gcc -o value value.o [email protected]:~/stuc/shuzu$ ./value a[0]=10 a[1]=11 a[2]=12 a[3]=13 a[4]=14 a[5]=15 a[6]=16 a[7]=17 a[8]=18 a[9]=19
3.数组名作函数参数
·显然与指针变量作函数参数是一致的,只是换个写法,即在定义或调用函数时,下面的功能是一致的:
a.创建函数时形式不一样,实际传递的还是指针:
void swap(int a[]) 等价于 void swap(int *a)
b.引用函数时,放入的都是指针:
swap(a) ===>实际放入的都是指针
·原理为:在编译时,最终数组引用的实现都是通过指针实现的;
4.指针与多维数组
--多维数组元素的指针
·创建一个如下的二维数组进行分析:
a[5][2] = {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}};
·只从文字数字上看,二维数组与指针的关系会比较抽象,可用下面的示意图形象化:
·作如下重要说明:
a.二维数组名实则是一个指针变量,包含了指向的存储单元和数据类型;
b.二维数组名指针变量指向的数据类型为:一维数组名,即指针变量;
c.所以二维数组名应为多重指针,即指向指针的指针;
d.前面说[ ]实则为取址运算符,则a[1],即为对多重指针a作运算:*(a+1),从而得到多重指针a指向的第2个指针变量;
e.*(a+1)或者说a[1]实则就是普通的一维数组名,也是一个指针,因此一维数组是如何处理的,即可对其作相应处理;
f.**(a+1)或者a[1][0],在这里就是对应的值3;
g.无论中间的指针指向如何复杂,根据数组的特性,最终的元素(在这里是数值),在内存中的存储空间是连续的。
--指向多维数组元素的指针变量
·根据一维数组和二维数组的特性,定义指向多维数组的指针变量时,有如下的两人种方式:
a.定义二维数组指针所指向的一维数组指针变量,与前面指针变量与一维数组是类似的;
b.定义指向二维数组名的二维数组指针变量,下面重点讨论;
·编写程序,通过指向二维数组的多重指针变量的运算来遍历二维数组:
<未完,continue>