c++:
2022找工作是学历、能力和运气的超强结合体,遇到寒冬,大厂不招人,此时学会c++的话,
我所知道的周边的会c++的同学,可手握10多个offer,随心所欲,而找啥算法岗的,基本gg
提示:系列c++学习的基础和高阶知识,用于公司生产实践中,实实在在的公司部署产品要用的,因为c++速度快,
而java和Python速度慢,自然往硬件里面部署算法啥的,都得用c++或者c,因此本科学的c很重要,后来的Python或者java就没有那么重要了,
c/c++系列文章:
【1】c++:c语言优缺点,visual studio2019如何新建项目,写hello world程序
【2】c/c++:gcc安装,gcc编译hello world文件,system函数调用系统命令,sleep函数
【3】linux下gcc的编译过程和功能,预处理,编译,汇编,链接,.c预处理为.i文件.s文件.o文件.exe文件
【4】c/c++:windows平台下依赖的动态库,c底层是汇编语言,程序断点调试,反汇编,vs快捷键
【5】c/c++:数据类型,常量变量,标识符,有符号整型,无符号unsigned,字符类型,字符串类型,实数类型,浮点型,科学计数法
【6】c/c++:2进制、8进制、10进制、16进制和进制之间的转换,c语言输出匹配格式%
【7】c/c++:原码,反码,补码和常见的数据类型取值范围,溢出
【8】c/c++:类型限定符,printf输出格式,putchar,scanf,getchar
【9】c/c++:算术运算符,赋值运算,逻辑运算,比较运算,三目运算,逗号运算,数据类型转换
【10】c/c++:顺序结构,if else分支语句,do while循环语句,switch case break语句
【11】c/c++:for循环语句,分号不可省略,表达式可以省略,猜数字游戏,跳转语句continue,break,避免写goto
【12】c/c++:一维数组,初始化数组,循环打印数组,计算数组存储空间,数组元素个数,数组逆序算法
【13】c/c++:二维数组,数组的行数和列数求法sizeof,数组初始化不同形式,5个学生,3门功课,求学生总成绩和功课总成绩
【14】c/c++:visual studio的代码快捷键,VS设置自定义默认代码,使用快捷键
【15】c/c++:三维数组,字符数组和字符串,统计字符串中字符出现的频次,scanf输入空格,正则匹配表达式
【16】c/c++:gets(),fgets(),puts(),fputs(),strlen(),字符串拼接函数
【17】c/c++:函数的作用,分类,随机数,函数定义,调用,申明,exit()函数,多文件编程,防止头文件重复
【18】c/c++:指针,指针定义和使用,指针大小4字节,野指针,空指针*p=NULL
【19】c/c++:万能指针,泛型指针,const int *p,int const *p,int *const p,const int *const p,指针与数组,p++,
文章目录
- c++:
- @[TOC](文章目录)
- c/c++:指针p+p-p*p/
- 数组名取地址+1
- 指针+指针
- 用指针实现strlen函数
- 指针的比较运算
- 指针数组
- 多级指针
- 总结
文章目录
- c++:
- @[TOC](文章目录)
- c/c++:指针p+p-p*p/
- 数组名取地址+1
- 指针+指针
- 用指针实现strlen函数
- 指针的比较运算
- 指针数组
- 多级指针
- 总结
c/c++:指针p+p-p*p/
void f67(void)
{
int a = 10;
int b = 20;
int* p = &a;
//printf("%p\n", p/2);//不能乘除?
}
指针不能做乘除运算
你把地址乘除有啥意义
加减是可以的
前后挪动多少字节
void f67(void)
{
int a = 10;
int b = 20;
int* p = &a;
//printf("%p\n", p/2);//不能乘除?
printf("%p\n", p + 2);//不能乘除?
printf("%p\n", p - 2);//不能乘除?
}
int main(void)
{
f67();
system("pause");
return 0;
}
数组中加减整数也是前后挪动一个位置
数组中说偏字节没用
就是挪动一个位置
左右移动地址
好说
数组名取地址+1
是啥?
void f68(void)
{//指针和数组
int a[] = { 1,2,4 };
int* p = a;//b本身就是地址
printf("%p\n", a);
printf("%p\n", &a[0]);
printf("%p\n", p+1);//这是取地址
printf("%p\n", a+1);//这是取地址
printf("%p\n", &a);//这是取地址
printf("%p\n", &a+1);//这是取地址---很猛
}
int main(void)
{
f68();
system("pause");
return 0;
}
发现了吗,&a+1,挪动了12个字节【即a数组大小】
a+1=p+1,是p+1挪动了一个字节而已,到下一个元素
而&a+1
是加整个数组的字节,p挪动到整个数组后面了
牛了这个
&a不是取数组首个地址【因为a=&a[0]】
而是整个数组的地址
所以你+1
加的是数组类型整个这么大的空间
指针+指针
void f69(void)
{
int a = 10;
int b = 20;
int* p = &a;
int* q = &b;
//printf("%p\n", p+q);//不可以操作
printf("%p\n", p);//可以操作
printf("%p\n", q);//可以操作
printf("%p\n", p-q);//可以操作
}
对于普通变量
指针可以减,不可以加
但是没意义
那要是数组呢?
void f70(void)
{//指针和数组
int a[] = { 1,2,3,4,5,6,7,8,9,0 };
int* p = &a[3];
printf("%p\n", p);//可以操作
printf("%p\n", a);//可以操作
printf("%p\n", p - a);//可以操作
}
int main(void)
{
f70();
system("pause");
return 0;
}
C=12=3个int自己
懂
实际也是类型这么个差距
int是3个这里
再看
void f70(void)
{//指针和数组
int a[] = { 1,2,3,4,5,6,7,8,9,0 };
int* p = &a[2];
printf("%p\n", p);//可以操作
printf("%p\n", a);//可以操作
printf("%p\n", p - a);//可以操作
}
偏移过的元素个数
数组中指针相减
是俩指针之间的元素的偏移个数
相加不允许哦
数组读完后,野指针p-a的话
就是整个数组的偏移个数,也是整个数组的大小
懂???
用指针实现strlen函数
非指针形式
int mystrlen(char str[]) {
//传入字符数组
//原来是
int i = 0;
while (str[i] != '\0') i++;
return i;//统计结果返回
}
void f71()
{
char str[] = "hello";
int len = mystrlen(str);
printf("%d\n", len);
}
int main(void)
{
f71();
system("pause");
return 0;
}
现在需要你用指针实现
int mystrlen2(char str[]) {
//传入字符数组
//指针实现
char* p = str;
while (*p != '\0') p++;
return p-str;//统计结果返回个数
}
void f71()
{
char str[] = "hello";
int len = mystrlen(str);
int len2 = mystrlen2(str);
printf("%d\n", len);
printf("%d\n", len2);
}
int main(void)
{
f71();
system("pause");
return 0;
}
字符串本质是字符数组
char类型的数组
我们把str的首地址赋给指针p
然后判断*p是否为\0
是则说明p已经来到了野指针的地方,p-str地址就是间隔char的个数,这就是我们要的字符串的长度
否则说明p还没有到字符串结尾,p++,挪动char的1个字节长度
如果这个代码写出来了
说明我们对指针的掌握已经很透了
美滋滋
函数的形参,在调用是,都是copy一份东西给它
函数内部就不用直接用实参
*p是解引用
左值是赋值,右值是获取内容
反正理解透了就好办了
p++在数组中是挪动类型个字节
指针的比较运算
void f72()
{
int a[] = { 1,2,3,4,5,6,7,8,9,0 };
int* p = a;
if (p > a)
{
printf("p>a\n%p\n", p);//可以操作
printf("%p\n", a);//可以操作
}
else if(p<a)
{
printf("p<a\n%p\n", p);//可以操作
printf("%p\n", a);//可以操作
}
else
{
printf("p=a\n%p\n", p);//可以操作
printf("%p\n", a);//可以操作
}
}
p指向一个地址
a是一个地址
反正地址大小是16进制的比较
int a1 = 10;
int b = 20;
//俩变量之间的地址没用没意义
int*指针类型
p指针变量
NULL等价于0地址
这个地址其实是操作系统不允许操作的地址
指针数组
之前我们搞的都是整型int数组
存整数
如果是指针数组呢?
存的是地址呗
void f73()
{
int a = 10;
int b = 20;
int c = 30;
int* p1 = &a;
int* p2 = &b;
int* p3 = &c;
int* arr[] = { p1,p2,p3 };//整型地址
//这就是指针数组,说白了就是房间号的地址
for (size_t i = 0; i < 3; i++)
{
printf("%p ", *arr[i]);//解引用
}
}
int main(void)
{
f73();
system("pause");
return 0;
}
注意中,这个解引用是abc的16进制数哦,就是abc
地址p123我们下面打印
申明p和a们
然后定义指针数组arr
低地址到高地址
分别存p1,2,3
实际存的就是地址咯
void f73()
{
int a = 10;
int b = 20;
int c = 30;
int* p1 = &a;
int* p2 = &b;
int* p3 = &c;
int* arr[] = { p1,p2,p3 };//整型地址
//这就是指针数组,说白了就是房间号的地址
for (size_t i = 0; i < 3; i++)
{
printf("%d ", *arr[i]);//解引用
printf("%p ", arr[i]);//arr指针地址本身
}
}
int main(void)
{
f73();
system("pause");
return 0;
}
arr[i]是p123这仨地址
而*arr[i]是对这仨地址的解引用,取出这三地址内部的abc变量
懂?
这里引出了二级指针
为啥呢,你数组里面存了指针,指针又是别的地址
所以是一个间接过程,二级地址
即二级指针
之前说了
arr[0]==*(arr+0)
arr名就是一个指针地址,偏移0之后解引用
这是数组取东西的本质
void f73()
{
int a = 10;
int b = 20;
int c = 30;
int* p1 = &a;
int* p2 = &b;
int* p3 = &c;
int* arr[] = { p1,p2,p3 };//整型地址
//这就是指针数组,说白了就是房间号的地址
for (size_t i = 0; i < 3; i++)
{
printf("%d ", *arr[i]);//解引用
printf("%p ", arr[i]);//arr指针地址本身
}
//看arr[0]
printf("\n%d ", *arr[0]);//解引用
printf("%d ", *(*(arr+0)));//解引用
printf("%d ", *(*(arr)));//解引用
printf("%d ", *(*arr));//解引用
printf("%d ", **arr);//解引用
}
一通变化之后
你发现是**arr
啥,2级指针
*arr是解引用内部地址
**arr是解引用这个地址代表的变量
2级指针
懂?
再看二维数组
void f74()
{
int a[] = { 10,10 };
int b[] = { 20 };
int c[] = { 30 };
int* p1 = a;
int* p2 = b;
int* p3 = c;
int* arr[] = { p1,p2,p3 };//整型地址
//这就是指针数组,说白了就是房间号的地址
for (size_t i = 0; i < 3; i++)
{
printf("%d ", *arr[i]);//解引用
printf("%p ", arr[i]);//arr指针地址本身
}
//看arr[0]
printf("\n%d ", *arr[0]);//解引用
printf("%d ", *(*(arr + 0)));//解引用
printf("%d ", *(*(arr)));//解引用
printf("%d ", *(*arr));//解引用
printf("%d ", **arr);//解引用
}
int main(void)
{
f74();
system("pause");
return 0;
}
说明二维数组也是二级指针
懂?
多级指针
一级指针是变量的地址
int a=10;
int*p=&a;//一级指针
int **p1= &p;//一级指针的地址,是二级指针
int ***p2=&p1;//二级指针的地址,是三级指针
二级指针是一级指针的地址
三级指针是二级指针的地址
int** p[]就是一个三级指针
存的是二级指针的地址,懂吧
三级指针解引用就是变量a本身
不管如何就是地址寻下一个地址
继续寻找下一个地址
最后找到真的东西即可
美滋滋
void f75()
{
int a = 10;
int* p = &a;
int** pp = &p;
int*** ppp = &pp;
printf("%p\n", ppp);
printf("%p\n", &pp);
printf("%p\n", pp);
printf("%p\n", &p);
printf("%p\n", p);
printf("%p\n", &a);
printf("%d\n", ***ppp);
printf("%d\n", **pp);
printf("%d\n", *p);
printf("%d\n", a);
}
int main(void)
{
f75();
system("pause");
return 0;
}
懂了吧,反正几级指针
你就几级引用即可
多级指针,不能跳跃定义
因为要一连串找地址,就像链表一样,懂了吧
总结
提示:重要经验:
1)
2)学好c++,即使经济寒冬,手握10个大厂offer绝对不是问题!
3)笔试求AC,可以不考虑空间复杂度,但是面试既要考虑时间复杂度最优,也要考虑空间复杂度最优。