为什么要使用指针
√ 函数的值传递,无法通过调用函数,来修改函数的实参
√被调用函数需要提供更多的“返回值”给调用函数
√减少值传递时带来的额外开销,提高代码执行效率
指针定义
#include <stdio.h>
#include <stdlib.h>
int main(void){
int age;
char ch;
//定义了一个指针
//指针本身也是一个变量
//名称是 p, 它是一个指针,可以指向一个整数
//也就是说: p 的值就是一个整数的地址!!!
int *p ;
char * c;
//指针 p 指向了 age
//p 的值,就是 age 的地址
p = &age;
c = &ch;
//scanf_s("%d", &age);
scanf_s("%d", p);
printf("age: %d\n", age);
system("pause");
return 0;
}
/*指针定义方式:
int *p; 或者 int *p1, *p2; (方式一)
int* p; (方式二)
int* p1,p2; (p1 是指针, p2 只是整形变量 )
int * p; 或者int*p;(不建议)
*/
指针的初始化
#include <stdio.h>
#include <stdlib.h>
int main(void){
int room = 2;
//定义两个指针变量指向 room
int *p1 = &room;
int *p2 = &room;
printf("room 地址:0x%p\n", &room);
printf("p1 地址:0x%p\n", &p1);
printf("p2 地址:0x%p\n", &p2);
printf("room 所占字节:%d\n", sizeof(room));
printf("p1 所占字节:%d\n", sizeof(p1));
printf("p2 所占字节:%d\n", sizeof(p2));
system("pause");
return 0;
}
/*注意:
32 位系统中,int 整数占 4 个字节,指针同样占 4 个字节
64 位系统中,int 整数占 4 个字节,指针占 8 个字节
*/
指针的访问
#include <stdio.h>
#include <stdlib.h>
int main(void){
int room = 2 ;
int * girl = &room;
int x = 0;
x = *girl;
//*是一个特殊的运算符,*girl表示读取指针girl所指向的变量的值,*girl相当于 room
printf("x: %d\n", x);
*girl = 4; //相当于 room = 4
printf("room: %d, *girl: %d\n", room, *girl);
system("pause");
return 0;
}
空指针和坏指针
什么是空指针?
空指针,就是值为 0 的指针。(任何程序数据都不会存储在地址为 0 的内存块中,它是被操作系 统预留的内存块。)
int *p = 0;
或者
int *p = NULL; //强烈推荐
空指针的使用:
(1)指针初始化为空指针
int *select = NULL;
目的就是,避免访问非法数据。
(2)指针不再使用时,可以设置为空指针
int *select = &a;
select = NULL;
(3)表示这个指针还没有具体的指向,使用前进行合法性判断
int *p = NULL;
// 。。。。
if (p) { //p 等同于 p!=NULL
//指针不为空,对指针进行操作
}
坏指针
int *select; //没有初始化
情形一
printf("选择的房间是: %d\n", *select); //此时select没有初始化,
//*select没有对应值
情形二
select = 100;
printf("选择的房间是: %d\n", *select);//select赋值100
//*select是地址为100的里面的值,
//但是地址为100和地址为0这样的地址都是被系统预留的内存块无法访问
渣男、直男、暖男的区别:const
#include <stdio.h>
#include <stdlib.h>
//const 和指针
int main(void){
int wife = 24;
int girl = 18;
//第一种 渣男型
int * zha_nan = &wife;
*zha_nan = 25;
zha_nan = &girl;
*zha_nan = 19;
printf("girl : %d wife: %d\n", girl, wife);
//第二种 直男型
//const int * zhi_nan = &wife; //第一种写法
int const * zhi_nan = &wife; // 第二种写法
//*zhi_nan = 26; 无法对数据进行修改,但是可以换老婆
printf("直男老婆的年龄:%d\n", *zhi_nan);
zhi_nan = &girl;
printf("直男女朋友的年龄:%d\n", *zhi_nan);
//*zhi_nan = 20; 无法对数据进行修改,但是可以换老婆
//第三种 暖男型
int * const nuan_nan = &wife;
*nuan_nan = 26;
printf("暖男老婆的年龄:%d\n", wife);
//nuan_nan = &girl; //可以对数据进行修改,但是为人专一不能换老婆
//第四种超级暖男型的
const int * const super_nuan_nan = &wife; //不允许指向别的地址,
//不能修改指向变量的值
//*super_nuan_nan = 28;
//super_nuan_nan = &girl;
system("pause");
return 0;
}
总结: 看 const 离类型(int)近,还是离指针变量名近,离谁近,就修饰谁,谁就 不能变
指针的算术运算
#include <stdio.h>
#include <stdlib.h>
int main(void){
int ages[]={21,15,18,14,23,28,10};
int len = sizeof(ages)/sizeof(ages[0]);
//使用数组的方式来访问数组
for( int i=0; i<len; i++){
printf("第%d 个学员的年龄是:%d\n", i+1, ages[i]);
}
//打印数组的地址和第一个成员的地址
printf("ages 的地址: 0x%p , 第一个元素的地址: 0x%p\n", ages, &ages[0]);
int *p = ages;
//访问第一个元素
printf("数组的第一个元素:%d\n", *p);
//访问第二个元素 //p++; // p = p+ 1*(sizeof(int))
//printf("数组的第二个元素:%d, 第二个元素的地址: 0x%p\n", *p, p);
for(int i=0; i<len; i++){
printf("数组的第%d 个元素:%d 地址:0x%p\n", i+1, *p, p);
p++;
}
printf("------------------------\n");
char ch[4]={'a','b','c','d'};
char * cp = ch;
for(int i=0; i<4; i++){
printf("数组的第%d 个元素:%c 地址:0x%p\n", i+1, *cp, cp);
cp++;
}
system("pause");
return 0;
}
总结: p++ 的概念是在 p 当前地址的基础上 ,自增 p 对应类型的大小 p = p+ 1x (sizeof(类型))
自减同理、指针与整数的加法、减法同理
指针与整数的运算 ,指针加减数字表示的意义是指针在数组中位置的移动;
对于整数部分而言,它代表的是一个元素,对于不同的数据类型,其数组的元素占 用的字节是不一样的, 比如指针 + 1,并不是在指针地址的基础之上加 1 个地址,而是在这个指针地址的 基础上加 1 个元素占用的字节数:
如果指针的类型是 char*,那么这个时候 1 代表 1 个字节地址;
如果指针的类型是 int*,那么这个时候 1 代表 4 个字节地址;
如果指针的类型是 float*,那么这个时候 1 代表 4 个字节地址;
如果指针的类型是 double*,那么这个时候 1 代表 8 个字节地址。
指针与指针之间的加减运算
#include <stdio.h>
#include <stdlib.h>
/*** (1)使用“指针-指针”的方式计算整数数组元素的偏移值; * */
int main(void){
int ages[] = {20,18,19,24,23,28,30,38, 35, 32};
int ages1[] = {18, 19, 20, 22};
int len = sizeof(ages) / sizeof(ages[0]);
int *martin = ages+6;
int *rock = ages+9;
printf("rock - martin = %d\n", rock - martin);
printf("martin - rock = %d\n", martin - rock);
martin = ages+6;
rock = ages1+3;
printf("martin: %p rock: %p rock-martin:%d\n",martin, rock ,rock-martin);
system("pause");
return 0;
}
总结:
(1)指针和指针可以做减法操作,但不适合做加法运算;
(2)指针和指针做减法适用的场合:两个指针都指向同一个数组,相减结果为两个指针之 间的元素数目,而不是两个指针之间相差的字节数。
(3)如果两个指针不是指向同一个数组,它们相减就没有意义