一、指针
1. 指针的重要性
表示一些复杂的数据结构
快速的传递数据,减少了内存的耗用
使函数返回一个以上的值
能直接访问硬件
能够方便的处理字符串
是理解面向对象语言中引用的基础
总结:指针是C语言的灵魂
2. 指针的定义
地址
内存单元的编号
从0开始的非负整数
范围:4G [0--4G-1]
指针
指针就是地址,地址就是指针
地址就是内存单元的编号
指针变量是存放地址的变量
指针和指针变量是两个不同的概念
但是要注意通常我们叙述时会把指针变量简称为指针,实际它们含义并不一样
指针的本质就是一个操作受限的非负整数
3. 指针的分类
1. 基本类型指针
2. 指针和数组
指针和一维数组
一维数组名
一维数组是个指针常量
他存放的是一维数组第一个元素的地址
下标和指针的关系
如果p是个指针变量,则
p[i] 永远等价于 *(p+i)
确定一个一维数组需要几个参数(如果一个函数要处理一个一维数组,则需要接收该数组的哪些信息)
需要两个参数:
数组第一个元素的地址
数组的长度
指针变量的运算
指针变量不能相加 不能相乘 也不能相除
如果两个指针变量只想的是同一块连续的空间中的不同的存储单元
则两个指针变量才可以相减
一个指针变量到底占几个字节
预备知识:
sizeof(数据类型)
功能:返回值就是该数据类型所占的字节数
例子: sizeof(int) = 4 sizeof(char) = 1
sizeof(double) = 8
sizeof(变量名)
功能:返回值是该变了所占的字节数
假设p指向char类型变量(1个字节)
假设q指向int类型变量(4个字节)
假设r指向double类型变量(8个字节)
p q r本身所占的字节数是否一样
答案: p q r 本身所占的字节都是一样的
总结:一个指针变量,无论它指向的变量占几个字节
该指针变量本身只占四个字节
一个变量的地址,是用该变量的地址使用该变量首字节的地址来表示。
指针和二维数组
3. 指针和函数
4. 指针和结构体
5. 多级指针
专题:
动态内存分配(重点难点)
传统数组的缺点:
1. 数组的长度必须事先制定,且只能是常整数,不能是变量
例子:
int a[5]; //Ok
int len = 5; int a[len]; //error
2. 传统形式定义的数组,该数组的内存程序员无法手动释放
在一个函数运行期间,系统为该函数中数组所分配的空间
会一直存在,直到该函数运行完毕时,数组的空间才会被
系统释放
3. 数组的长度一旦定义,其长度就不能再更改
数组的长度不能在函数运行的过程中动态的扩充或缩小
4. A函数定义的数组,在A函数运行期间可以被其他函数使用,
但A函数运行完毕之后,A函数中的数组将无法在被其他函数使用。
传统方式定义的数组不能跨函数使用
为什么需要动态内存
动态数组很好的解决了传动数组的这4个缺陷
传动数组也叫静态数组
动态内存分配举例_ 动态数组的构造
静态内存和动态内存的比较
静态内存是由系统自动分配,由系统自动释放
静态内存是在在栈分配的
动态内存是由程序员手动分配,手动释放
动态内存是在堆分配的
跨函数使用内存的问题
4. *的含义
1. 乘法
2. 定义指针变量
int * p;(int * p 和 *p = 5 此时*号的含义不一样)
//定义了一个名字叫p的变量, int * 表示p只存放变量的地址
3. 指针运算符
该运算符放在已经定义好的指针变量的前面
如果p是一个已经定义好的指针变量
则 *p表示以p的内容为地址的变量
5. 如何通过被调函数修改主调函数普通变量的值
1. 实参必须为该普通变量的地址
2. 形参必须为指针变量
3. 在被调函数中通过
*形参名 = .....
的方式就可以修改主调函数相关变量的值
二、指针简单介绍

1 #include <stdio.h> 2 #include <stdlib.h> 3 int main() 4 { 5 int *p; //p是变量的名字,int * 表示p变量存放的是int类型的地址 6 int i = 3; 7 8 p = &i; //OK 9 //p = i; //error,因为类型不一致,p只能存放int类型变量的地址,不能存放int类型变量的值 10 //p = 55; //error,原因同上。 11 system("pause"); 12 return 0; 13 }

1 #include <stdio.h> 2 #include <stdlib.h> 3 int main() 4 { 5 int * p; //p是变量的名字,int * 表示p变量存放的是int类型的地址 6 //int *p ; 不表示定义的一个名字叫做*p的变量 7 //int *p ; 应该这样理解:p是变量名,p变量的数据类型是int *类型 8 // 所谓int * 类型 实际就是存放int变量地址的类型 9 int i = 3; 10 int j; 11 12 p = &i; 13 /* 14 1. p保存的i的地址,因此p指向i 15 2. p不是i,i也不是p,更准确的说:修改p的值不影响i的值,修改i的值也不影响p的值 16 3. 如果一个指针变量指向某个普通变量,则*指针变量 就完全等同于 普通变量 17 例子: 18 如果p是个指针变量,并且存放了普通变量i的地址 19 则p指向了普通变量i 20 *p 就完全等同于 i 21 或者说:在所有出现*p的地方都可以替换成i 22 在所有出现i的地方都可以替换成*p 23 24 25 *p就是以p的内容为地址的变量 26 27 */ 28 j = *p; //等价于 j = i; 29 printf("i = %d, j = %d ",i,j); 30 system("pause"); 31 return 0; 32 } 33 34 /* 35 指针就是地址,地址就是指针 36 地址就是内存单元的编号 37 指针变量是存放地址的变量 38 指针和指针变量是两个不同的概念 39 但是要注意通常我们叙述时会把指针变量简称为指针,实际它们含义并不一样 40 41 */

1 #include <stdio.h> 2 #include <stdlib.h> 3 int main() 4 { 5 int *p; 6 int i = 5; 7 8 p = &i; //没有这一步 这个程序就是错误的 9 *p = i; 10 printf("%d ",*p); 11 system("pause"); 12 return 0; 13 }

1 #include <stdio.h> 2 #include <stdlib.h> 3 int main() 4 { 5 int * p; 6 int * q; 7 int i = 5; 8 9 p = &i; 10 //*q = p //error 语法编译会出错 11 //*q = *p //error 12 p = q; //q是垃圾值,q赋给p,p也变成垃圾值 13 printf("%d ",*q); 14 /* 15 q的空间是属于本程序的,所以本程序可以读写q的内容, 16 但是如果q内部是垃圾值,则本程序不能读写*p的内容 17 因为*q所代表的内存单元的控制权限并没有分配给本程序 18 所以本程序运行到13行就会立即出错 19 */ 20 system("pause"); 21 return 0; 22 }

1 #include <stdio.h> 2 #include <stdlib.h> 3 4 void huhuan(int a, int b ) 5 { 6 int t; 7 8 t = a; 9 a = b; 10 b = t; 11 12 return; 13 } 14 15 16 int main() 17 { 18 int a = 3; 19 int b = 5; 20 21 huhuan(a,b); 22 23 printf("%d %d",a,b); 24 25 system("pause"); 26 return 0; 27 } 28 /* 29 30 这个程序是错误的 31 */

1 #include <stdio.h> 2 #include <stdlib.h> 3 //不能完成互换功能 4 void huhuan(int * p , int * q ) 5 { 6 int * t; //如果要互换p和q的值,则t必须是int *,不能是int,否则会出错 7 8 t = p; 9 p = q; 10 q = t; 11 12 13 return; 14 } 15 16 17 int main() 18 { 19 int a = 3; 20 int b = 5; 21 22 huhuan(&a,&b); //huhuan_2(*p,*q);是错误的,huhuan(a,b);也是错误的 23 24 printf("%d %d",a,b); 25 26 system("pause"); 27 return 0; 28 } 29 /* 30 31 这个程序是错误的 32 */

1 #include <stdio.h> 2 #include <stdlib.h> 3 void huhuan(int * p , int * q ) 4 { 5 int t; //如果要互换*p和*q的值,则t必须的定义成int,不能定义成 int*,否则语法会出错 6 7 t = *p; //p是int *, *p是int 8 *p = *q; 9 *q = t; 10 11 12 return; 13 } 14 15 16 int main() 17 { 18 int a = 3; 19 int b = 5; 20 21 huhuan(&a,&b); //huhuan_2(*p,*q);是错误的,huhuan(a,b);也是错误的 22 23 printf("%d %d",a,b); 24 25 system("pause"); 26 return 0; 27 } 28 /* 29 这个程序是正确的 30 */

1 #include <stdio.h> 2 #include <stdlib.h> 3 int main(void) 4 { 5 int * p; //等价于int *p; 也等价于 int* p; 6 int i = 5; 7 char ch = 'A'; 8 9 p = &i; // *p 以p的内容为地址的变量 10 *p = 99; 11 printf("%d ",i); 12 //p = &ch; //error 不能是字符变量地址 13 //p = ch; //error 14 // p = 5; //error 15 16 system("pause"); 17 return 0; 18 }

1 #include <stdio.h> 2 #include <stdlib.h> 3 4 //f函数可以输出任何一个一维数组的内容 5 void f(int * pArr, int len) 6 { 7 int i ; 8 9 for(i=0; i<len; ++i) 10 printf("%d ",*(pArr+i)); //*pArr *(pArr+1) *(pArr+2) 11 printf(" "); 12 } 13 int main(void) 14 { 15 int a[5] = {1,2,3,4,5,6}; 16 int b[6] = {-1,-2,-3,-4,5,-5}; 17 int c[100] = {1,99,22,33}; 18 19 f(a,5); 20 f(b,6); 21 f(c,100); 22 23 system("pause"); 24 return 0; 25 }

1 #include <stdio.h> 2 #include <stdlib.h> 3 4 void f(int * pArr, int len) 5 { 6 int i; 7 for(i=0; i<len; ++i) 8 printf("%d ",pArr[i]); //*(pArr+i0等价于 pArr[i] 也等价于b[i] 也等价于 *(b+i) 9 } 10 int main(void) 11 { 12 int b[6] = {1,2,3,4,5,6}; 13 f(b,6); 14 b[i] 15 system("pause"); 16 return 0; 17 }

1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int main(void) 5 { 6 int i = 5; 7 int j = 10; 8 int * p = &i; 9 int * q = &j; 10 int a[5]; 11 p = &a[1]; 12 q = &a[4]; 13 printf("p和q所指向的单元相隔%d个单元 ",q-p); 14 system("pause"); 15 return 0; 16 }

1 #include <stdio.h> 2 #include <stdlib.h> 3 int main() 4 { 5 6 char ch = 'A'; 7 double x = 66.6; 8 int i = 99; 9 char *p = &ch; 10 int *q = &i; 11 double *r = &x; 12 printf("%d %d %d",sizeof(p),sizeof(q),sizeof(r)); 13 14 system("pause"); 15 return 0; 16 }

1 #include <stdio.h> 2 #include <stdlib.h> 3 void g(int * pArr, int len) 4 { 5 pArr[2] = 88; //pArr[2] == a[2] 6 } 7 8 void f(void) 9 { 10 int a[5] = {1,2,3,4,5}; //20个字节的存储空间程序员无法手动编程释放它 11 //它只能在本函数运行完毕时由系统自动释放 12 g(a,5); 13 printf("%d ",a[2]); 14 } 15 16 int main(void) 17 { 18 19 f(); 20 system("pause"); 21 return 0; 22 }

1 /* 2 malloc 是 memory(内存) allocate(分配)的缩写 3 */ 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <malloc.h> //不能省 8 9 int main(void) 10 { 11 int i = 5; //分配的4个字节 静态分配 12 int * p = (int *)malloc(4); 13 /* 14 1. 要使用malloc函数,必须添加malloc.h,这个头文件 15 2. malloc函数只有1个形参,并且形参是整数类型 16 3. 4表示请求系统为本程序分配4个字节 17 4. malloc函数只能返回第一个字节的地址 18 5. 12行分配了8个字节,p变量占4个字节,p指向的内存也占4个字节 19 6. p本身所占的内存是静态的分配的,p所指向的内存是动态分配的 20 */ 21 *p = 5; //*p 代表的就是一个int变量,只不过*p这个整型变量的内存分配方式和11行的i变量分配方式不同 22 free(p); //free(p)表示把p所指向的内存释放掉,p本身的内存是静态对,不能有程序员手动释放,p本身的内存只能在p变量所在的函数运行终止时由系统自动释放 23 printf("同志们好! "); 24 system("pause"); 25 return 0; 26 }

1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <malloc.h> 4 5 void f(int * q) 6 { 7 //*p = 200; //error 8 //q = 200; //error 9 *q = 200; 10 //free(q); //把q所指向的内存释放掉 , 本语句必须得注释掉,否则会导致第20行的代码出错 11 } 12 int main(void) 13 { 14 int *p = (int *)malloc(sizeof(int)); //sizeof(int)返回值是int所占的字节数 15 *p = 10; 16 17 printf("%d ",*p); 18 f(p); //p是int *类型 19 printf("%d ",*p); 20 21 system("pause"); 22 return 0; 23 }

1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <malloc.h> 4 5 int main(void) 6 { 7 int a[5]; //如果int占4个字节的话,则本数组总共包含20个字节,每四个字节被当作一个int变量来使用 8 int len; 9 int * pArr; 10 int i; 11 12 //动态的构造一维数组 13 printf("请输入你要存放的元素的个数:"); 14 scanf("%d",&len); 15 pArr = (int *)malloc(4*len); //本行动态的构造了一个一维数组,该一维数组的长度是len ,该数组的数组名是pArr,该数组的每个元素是int类型,类似于 int pArr[len]; 16 17 //对一维数组进行操作 18 //对动态一维数组进行赋值 如:对动态一维数组进行赋值 19 for(i=0; i<len; ++i) 20 scanf("%d",&pArr[i]); 21 22 //对一维数组进行输出 23 printf("一维数组的内容是: "); 24 for(i=0; i<len; ++i) 25 printf("%d ",pArr[i]); 26 27 free(pArr); //释放掉动态分配的数组 28 system("pause"); 29 return 0; 30 }

1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <malloc.h> 4 5 int main(void) 6 { 7 int i = 10; 8 int * p = &i; 9 int ** q = &p; 10 int *** r = &q; 11 12 //r = &p; //因为r是int ***类型,r只能存放int **类型变量的地址 13 printf("i = %d ",***r); 14 15 system("pause"); 16 return 0; 17 }

1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <malloc.h> 4 5 void f(int *** r) 6 { 7 int i = 15; 8 **r = &i; 9 10 } 11 int main(void) 12 { 13 int i = 10; 14 int * p = &i; 15 int ** q = &p; 16 17 printf("%d ",**q); 18 19 f(&q); 20 printf("%d ",**q); 21 system("pause"); 22 return 0; 23 }

1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <malloc.h> 4 5 void f(int ** q) 6 { 7 8 **q = 1000; 9 } 10 11 void g() 12 { 13 int i = 10; 14 int * p = &i; 15 f(&p); 16 printf("%d ",*p); 17 } 18 int main(void) 19 { 20 g(); 21 system("pause"); 22 return 0; 23 }

1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <malloc.h> 4 5 void f(int ** q) //q是个指针变量,无论q是什么类型的指针变量,都只占4个字节 6 { 7 int i = 5; 8 //*q等价于p q和**q都不等价于p 9 //*q = i; //error 因为*q = i; 等价于 p = i;这样写是错误的 10 *q = &i; //p = &i; 11 } 12 int main(void) 13 { 14 int *p; 15 f(&p); 16 // 15行已经把f()给释放了 17 printf("%d ",*p); //本语句语法没有问题,但逻辑上有问题。 18 19 system("pause"); 20 return 0; 21 }

1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <malloc.h> 4 5 void f(int ** q) 6 { 7 *q = (int *)malloc(sizeof(int)); //sizeof(数据类型)返回值是该数据类型所占的字节 8 //等价于 p = (int *)malloc(sizeof(int)); 9 //q = 5; 10 //*q = 5; //error p = 5; 11 **q = 5;//*p = 5; 12 } 13 int main(void) 14 { 15 int *p; 16 f(&p); 17 18 printf("%d ",*p); 19 20 system("pause"); 21 return 0; 22 }