Part1前言
准备转行跑路了,先回味回味 c++,遥感的局限还是太大了,在一个没有资源的情况下,却一定要去凑一些东西,感觉与其三年都做无谓的数据了,不如早点转开发保平安,遥感就随缘看看吧,深度学习,学了个寂寞,调包调参侠,有啥意思,后续反正周六和晚上 c++,计组、计网、操作系统。平常打工,遥感有啥新奇的事,深度学习有啥有趣的事就随缘写写呗。
这个公众号本身就随缘玩的,随缘写的,我开心就好!
在看 Primer c++ 第 5 版,本科的时候 c++ 学了跟没学一样,但是为了数据结构,为了工作,还是得好好学 c++ 呀,虽然不知道有多少遥感的朋友在看这个公众号,但是我决定还是先跑路了。想起了本科室友的哥哥,在空天院学遥感也学计算机转开发跑路去了。我只能说,这几个月下来,我只看到了“学术”上的遥感,看不到任何工业上的遥感,看不到
Part2序言
1经典 cin 和 cout
#include<iostream>
using namespace std;
int main(){
std::cout<< "Hello World"<<std::endl;
}
经典 Hello World
,但是读这本经典的书看到什么现在回去理解总会有不同的感受
#include<iostream> 库告诉编译器 (compiler)
使用的是 iostream
库,和 \usepackage{}、import ..
差不多。iostream
头文件
iostream
库,包含两个基础类型 istream
和 ostream
分别表示输入流和输出流。
<<
运算符接受的是两个运算对象,左侧为 ostream
的对象,右侧为打印的值,
对于 std::cout<<"Hello World"<<std::endl;
就等价于
(std::cout<<"Enter two numbers:") << std::endl
相当于分别执行了:
std::cout<<"Hello World" ;
std::cout<<std::endl;
第二个运算符打印 endl
,被称为操作符,写入 endl
表示结束当前行
而对于 std::
来说,指出 cout
和 endl
是定义在 std
的命名空间(namespace)
中的,命名空间可以避免不经意的定义冲突。与 <<
对应的就是 >>
表示的是,左侧接受一个 istream
作为左侧运算对象,接受一个对象为右侧运算对象。
2注释:
//
表示单行注释, /* */
表示多行注释,但是注释不能嵌套,
3while 语句
经典的 i++
和 ++i
, i++
表示先引用 i
的值,i
再加 1,而 ++i
表示先进行 i = i +1
再将新的值取出。
对于输入不定量的值的时候可以将 cin
放在 while 里面,
4小综合应用呗
#include<iostream>
using namespace std;
int main(){
int currVal = 0, val = 0;
//如果确实有输入
if(cin >> currVal){
int cnt = 1;
while(cin >> val ){
if(val == currVal)
cnt += 1;
else{
cout << currVal << " Occurs" << cnt << "times" <<endl;
#将输入的变量存储到 currVal 中去
currVal = val;
cnt = 1;
}
}
cout << currVal << "occurs" << cnt << "times" << endl;
}
reutrun 0;
}
但是这个程序有个小 bug,没有经典的 keyboardinterrupt
,然后对于同一值 val
一直让 currVal = val
。
Part3基本的变量
对于 c++ 来说,有符号和无符号不能混用 int a= 1,unsigned b = -1
,但是 a * b = 4294967295
.
对于无符号变量来说,它永远不会小于 0 ,所以就牵涉到了 for
循环还有 while
循环里是否先进行减法的问题。
for (unsigned u = 10;u >= 0;u -- ){
cout << u;
}
由于迭代成 0 之后,然后继续执行 for 语句里面的内容,表达式 --u
从从当 u
中减去 1,得到的结果 -1 不满足符号的要求,-1
被转换成合法的无符号数,如果 int
占 32 位,则当 u
等于 0 时, --u
的结果会是 4294967295
,如果使用 while
来代替 for
循环,则会先进行一次判断,然后再转
初始化和赋值是有区别的,初始化只是创建一个变量赋予一个初始值,而赋值是把对象的当前值给擦除。
对于 c++ 来说有 extern
声明和定义
两种形式,而声明的值在函数体内部不能够初始化,例如:
int main(){
extern int i;
int j = 1;
i = 1;
}
就会报错
而如果在 main
函数之外,直接用 extern int i = 1
;程序能够正常编译运行。
变量能够被定义一次,但是可以被多次声明.
如果在多个文件中使用同一个变量,必须将声明和定义分离,变量的定义只能出现在一个文件中,而其他用到该变量的文件必须对其就行申明。却绝对不能重复定义。
静态语言
c++ 是一种静态的语言,即,在编译检查阶段,进行类型的检查,如果不支持运算,则程序会报错并且不会生成可执行程序。
而程序越复杂,静态检查就更容易发现问题,前提是编译器知道每一个实体对象的类型,所以,在使用每个对象前必须声明其类型。
对于 c++ 来说,有些规则是不被允许的。
不能连续出现两个下划线。 也不能以下划线紧跟大写字母连着。 定义在函数体外的标识符不能以下划线开头。
定义的几条规范:
标识符体现实际的含义 变量名一般用小写开头。 用户自定义的类名一般以大写开头 如果标识符由多个单词组成,单词之间应该有明显的区分, 例如 student_name
5引用
引用一般为左值引用,例如 int val = 1
, int &refVal = ival;
一般在初始化变量时,变量是被拷贝到新建的对象中。然而定义引用的时候,程序把引用和它的初始值绑定在一起,而并非直接将初始值拷贝给引用,引用将它的初始值一直绑定在一起,所以无法重新绑定到另一个对象,所以引用必须初始化。
引用并不是对象,只是为已经存在的对象起另外一个名字。
例如 int i = 1024, &r = i;
cout << r <<endl;
输出的是它的值,&r
则是输出的它的地址。而它的地址会与 i
的地址一样。由于是绑定, 所以,引用和被引用的对象的类型必须是一致的,同时,引用的必须是一个对象,而非一个常量,例如 int &ref4 = 10;
就会报错。
而一旦引用,引用和被引用的对象就被绑定在一起,例如:
int i , &ref = i;
i = 5;
ref = 10;
cout << i << " "<< ri <<endl;
程序输出的是 10,10
就说明两者已经被绑定在一起了,即这个引用不是单独的一个对象了。
6指针
指针应该是最难的了!!当年本科就没学明白,
指针本身就是一个对象,允许对指针进行拷贝和赋值,而指针在其有效时能够指向不同的对象,指针可以不定义初始值。
但是现在回来看指针,一下就看明白了!!
int ival = 42;
int *p = &ival;
指针指向的是对象的地址,例如:
int ival = 42;
int *p = &ival;
cout << "p 的地址是 " << p << "\n" << "p 的值是" << *p << endl;
所以还可以进行套娃,即:
int main(){
int i = 12;
int *p = &i;
int *p2 = p;
//输出的都是值
cout << i << "\t" << *p << "\t" << *p2 << endl;
}
而指针的类型实际上用于它所指向的对象的类型,所以二者必须匹配。
指针的值
指针的应该属于四种状态。
指向一个对象。
指向下一个对象所占的空间的下一个位置。
空指针,意味着没有指向任何对象。
无效指针,也就是上述情况的其他值。
一旦指针指向了一个对象,就可以解引
,解引用虽然可以能够改变指针变量的值
,但是同时也修改了它指向对象的值
,实际上也是间接的修改了原来指向的变量
。。
例如
int main(){
int i = 1;
int *p = &i;
// p 是一个地址,而 *p 是一个值,相当于解引用
cout << p << *p << endl;
*p = 0;
cout << p << *p;
cout << i
}
指针是个很 abstract 的问题,实际上,只需要记住 *
是取值的操作,而 &
是取地址的操作。在初始化指针变量的时候,实际上,*p = &i
就是将这个指针指向了 i
的地址,而 *p
则代表了一个解引用,能够解出 i
的值。
后续就会有一堆的问题,比如,引用
和 取址
符号,还有指针的解引用。
例如:
int main(){
int i = 42;
int &ref = i; //引用
int *p = &i; //指针指向
*p = i; //解引用
int &ref2 = *p; // 引用指针变量的值
}
空指针的值
int main{
int *p = nullptr;
int *p2 = 0;
// 要用到 <cstdlib> 这个库
int *p3 = NULL;
}
书上说:新版最好用 nullptr
这个方法,尽量同时避免 NULL
的方法。
书上也同时建议:
同时初始化所有的指针。
因为访问未经初始化的指针引发后果无法预计,造成了程序崩溃,一旦崩溃,就很难再找到出错的位置。
其他指针的操作
void* 是一种特殊的指针,可以用于存放任意对象的地址。一个 *void
指针存放着一个地址,但是无法知道到底是个什么类型的对象。
利用 void*
指针能做的事比较有限;拿他和别的指针比较,作为函数的输入和输出,或者赋值给另一个void *
指针,不能直接操作 void*
所指向的对象,因为不知道所指向对象的类型。
同样指针也能够进行判断,但是无法知道是 0
值还是空指针
int main{
int *p = 0; // 空指针
int i = 42;
int *p1 = &i;
if(*p)
cout<< "p指针合法"<<endl;
else if(*p1){
cout<< "p1 指针合法"<<endl;
}
}
但是由于空指针的值是 0
,在判断是否为 True 或者 False 会报错。
复合类型的声明
一条语句能够定义出不同类型的变量,例如:
int i = 42, *p = &i, &ref = i;
在这里即创建了一个 int
的变量,也创建了一个指针,也创建了一个引用的变量。
对于定义变量的类型,有不同的方法:
//方法1
int* p1, *p2;
//方法2
int *p1;
int *p2
着两种定义 int
型指针的方法都可行,但是需要按照一种去写,否则乱则生变??
指针可以套娃:
int i = 2;
int *p = &i;
int **p1 = &p;
cout << i<< endl; //直接输出原值的值
cout << "一次指针 p 的地址为: " << p << "," << "它的值为:" << "*p" <<endl; //一次指针
cout << "二次指针 ** p 的地址为:"<< *p << "," << "它的值为" << **p <<endl;
所以在套娃的时候很容易混乱到底在用地址还是在引用值。
指向指针的引用
int i = 2,*p;
int *&r = p;
r = &i;
*r = 0;
指向指针的引用:
这玩意儿看了我半个多小时,一直不理解,看了半天发现之前理解错了,总觉得怪怪的。
其实做了这么些事儿:
创建了一个
int
型的变量和一个int
型的指针变量。而由于指针本身就是一个对象,能够进行引用,所以,由于要引用指针,所以r
也得是一个指针,不过&r
相当于进行了一个引用。由于
r
还是一个指针的变量,所以需要拿到地址,由于r
这个指针还需要拿到i
的地址,这时候r
也指向了i
,这时候, 解引用r
并进行操作就会改指向的值。
例如:
int main{
int i = 42;
int &ref = i; // 引用 i ,这时候 引用的 ref 和 i 已经绑定在一起了,但是实际上并不存在 ref 这个变量
int *p = ref; // 所以这样创建指针,就相当于是错误 但是程序 仍能够运行
// int *p = &ref; //这样当然可以,因为 ref 这个引用已经和 i 捆绑在一起了。
cout << "指针指向的值是 " << *p <<endl;
}
所以从左到右阅读这些定义,是最有效搞清楚这些的办法。
实际上指针变量只是在函数体内部局部修改,没法作用到指针变量。而指针的引用能够作用到原指针变量。
7常量
const int bufsize = 512;
bufsize = 1; //这样是不被允许的,因为它已经被定义为一个常量了
初始化与 const
由于 const
变量一创建就不能改变,const
变量就一定得初始化,这与引用一致。但是 const
的值可以是任意一个复杂的表达式。但是 const
在默认的情况下,只会在文件内有效,比如,在一个文件中,bufsize
是一个 const
对象,那么文件就会找到 bufsize
然后把他们都赋值成 512
.
在多个文件中共享 const
变量
如果想在多个文件中共享同一个常量的话,需要用 extern
声明这一功能。
const
的引用
为了把引用绑定到 const
上面,可以对常量进行引用。
例如:
const int ci = 1024;
const int &ref = ci; //可以这样引用。
下面两种方法都是错误的:
ref = 42;
int &r2 = ci;
无法直接直接修改 ref 那么就无法直接修改,同样由于 常量无法修改,那么其对应的引用也就无法修改。
常量引用是对 const 的引用:
对
const 的引用
简称为常量引用
const 引用和 普通的引用还不一样.
指针和常量
要想存放常量的地址,只能使用常量的指针:
int main(){
const double pi = 3.14;
const double *p = π //正确写法
// double *p = π //错误写法
*p = 512; // 由于指向常量,无法修改
}
一个晕晕的例子
int i = 0;
int *const p1 = &j;
const int j = 1;
const int *p2 = &j;
从左到右去读代码,先找最近的符号,对于 p1
来说,最近的是 const
说明他是一个常量对象,然后接下来是 *
,说明它是一个常量指针,最后是一个 int
说明它指向的是一个 int
类型的数。 而对于 p2
,最近的是 *
说明他它是一个指针,然后是 const int
说明它指向的是一个int
类型的常量。
接下来就更晕了!
p1
是一个常量指针,但是并不意味着它不能修改其所指对象的值,例如:

那么,这个常量指针指向的值是 int
类型,当然可以通过解引用
的方法修改它的值。
而第二种,由于指向了一个常量的对象,想通过解引用
的方法去改原始的值,那么其实是不实际的。

例如,看下面的问题就已经很明显了,第一篇就写到这吧。
再说学好了 c++ 和 java 还怕搞不明白 python ??




