在学习指针之前,有些话要说一下:
1. 不要跟直接领导起冲突2. 你站的一方,有利益并且对你好3. 你站的一边,背后有更大的靠山4. 你站的一边,没有人和你有利益冲突5. 如果缺乏以上的判断力,请保持佛系-中立
核心思想: 子程序应该不因传入错误数据而被破坏,哪怕是由其他子程序产生的错误数据。这种思想是将可能出现的错误造成的影响控制在有限的范围内。
#include void assert( int expression )
例如上节课做的那个项目判断峰点时可以使用断言:
bool isPeak(int grid[N][N], int r, int c) {
assert(0 < r && r < N - 1);
assert(0 < c && c < N - 1);
if ((grid[r][c] > grid[r - 1][c]) &&
(grid[r][c] > grid[r + 1][c]) &&
(grid[r][c] > grid[r][c - 1]) &&
(grid[r][c] > grid[r][c + 1])) {
return true;
}
else {
return false;
}
}
进入今天的主题:指针!!
1、函数的值传递,无法通过调用函数,来修改函数的实参2、被调用函数需要提供更多的“返回值”给调用函数,靠值传递行不通3、减少值传递时带来的额外开销,提高代码执行效率
我们看一个代码:
#include
using namespace std;
void add_blood(int blood) {
blood += 1000;
}
int main() {
int blood = 90;
add_blood(blood);
cout << blood << endl;
}
运行结果:
这个运行结果说明不能通过传递值来改变实参的值。
把代码更新一下:
#include
using namespace std;
int add_blood(int blood) {
blood += 1000;
return blood;
}
int main() {
int blood = 90;
add_blood(blood);
cout << blood << endl;
blood=add_blood(blood);
cout << blood << endl;
}
运行结果:
虽然函数可以通过返回类型来改变值,但是如果在主函数中不更新变量,那么该变量的值还是不会改变,如我们仅仅只是调用add_blood()函数,是不会改变实参的值!要把返回的值赋值给该变量才能改变!
那么能不能不通过返回值就直接改变实参的值呢?答案是可以,用指针!
看一个代码,来理解指针的定义:
#include
#include
int main(void) {
int age;
char ch;
int* p;//定义一个int型指针
char* c;//定义一个char型指针
p = &age;//指针p指向了age,p的值就是age的地址
c = &ch;
scanf_s("%d", p);//等价于scanf_s("%d", &age);
printf("age: %d\n", age);
system("pause");
return 0;
}
运行结果:
指针的定义:数据类型* 指针变量名,例如:int *p;
指针本身也是一个变量,用来存储地址,不能用来存储其他数据!
名称是 p, 它是一个指针,可以指向一个整数变量的地址。
也就是说: p 的值就是一个整数的地址!!!
画个图理解:
int age=18;
int *p=&age;
假如变量age的地址是888,那么指针p的值就是888,它存的是age的地址,我们也可以说指针p指向了变量age。
第一种定义方式:int *p;int *p1, *p2; 定义两个指针变量,推荐这种定义方式!第二种定义方式:int* p;int* p1,p2; 注意,这里不是一下子定义了两个指针变量,p1 是指针, 但是 p2 只是整形变量,这里很容易出错,因此一个好的定义方式是方式1。把*和变量名写在一块,可增强代码可读性!第三种定义方式:int * p; 不常用第四种定义方式int*p; 不建议这种定义,可读性差!
#include
#include
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("p1 的值是%p\n", p1);
printf("p2 的值是%p\n", p2);
printf("room 所占字节:%d\n", sizeof(room));
printf("p1 所占字节:%d\n", sizeof(p1));
printf("p2 所占字节:%d\n", sizeof(p2));
}
运行结果:(我这里实在64位平台下运行的!)
先声明一点!指针变量所占的字节大小在32位平台是4个字节,在64位平台是8个字节!可以看到p1和p2的值就是变量room的地址。
画图理解:
注意:再次强调!32 位系统中,int 整数占 4 个字节,指针同样占 4 个字节64 位系统中,int 整数占 4 个字节,指针同样占 8 个字节
先看一个代码:地址的打印
#include
#include
int main(void) {
int room1 = 2;
int room2 = 3;
int* p1 = &room1;
int* p2 = p1;//等价于int *p2 = &room1;
//1.访问(读、写)指针变量本身的值,和其它普通变量的访问方式相同
int* p3 = p1;
printf("room 的地址: %p\n", &room1);
printf("p1 的值: %p p2 的值: %p\n", p1, p2);
printf("p3 的值: %p\n", p3);
printf("--------------------\n");
p3 = &room2;
printf("p3 的值: %p, room2 的地址:%p\n", p3, &room2);
printf("p1=0x%p\n", p1);
printf("p1=0x%x\n", p1);
printf("p1=0x%X\n", p1);
}
运行结果:
这里没啥好说的,理解即可,主要就是地址是一个无符号数,我们一般用%p打印,%x也是打印16进制的数,但是还是建议用%p,通过上面我们看到,%x或者%X它虽然是以16进制打印数据,但是它不能自动填充0。所以打印地址还是用%p格式打印!
%p可以在前面自动补0,如果一个地址换成16进制 后只有6位,那么%p形式会自动在前2个位置补0,而 %x不会自动补0。
再看代码,指针的解引用:
#include
#include
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);
}
运行结果:
这个结果说明,*gril等价于room,对*girl改变就是改变room。我们在定义的时候符号*是起到定义指针的作用,在非定义时,它是解引用和乘法操作符号。看图理解: