{
"terminal.external.windowsExec": "C:\\WINDOWS\\System32\\bash.exe",
"terminal.integrated.shell.windows": "C:\\WINDOWS\\System32\\bash.exe"
}
$ sudo apt install build-essential vim git cmake make
至此我们的准备工作才算完成了
int main(int, char **)
{
return 0;
}
$ g++ main.cc
$ ./a.out
$ g++ main.cc -o main # 使用-o 选项指定成的可执行文件名, 这里用的是main
$ ./main
以上的终端命令一般情况下都是没有任何输出打印的内容的,如果打印了一些报错信息, 请检查main.cc中的代码是否有拼写错误以及中英文符号错误
如果我们希望在代码中加入一些打印文本的代码, 下一步该怎么做呢?
别急, 慢慢来
两种方案:
面向过程:
int main(int, char**)
{
printf("Hello, C++");
return 0;
}
赶紧编译试试? 不好, 报错了,提示找不到printf的声明…尴尬!!!
怎么才能使用这个函数呢?
自己声明一个或者…引入现成的呗
怎么引入呢?
在文件的上面加一句文件包含就好啦 #include <文件名> 或者 #include “文件名”
要引入哪个头文件啊?
printf函数是标准C库里的函数呀, 当然得包含标准C库头文件了 #include
赶紧试试
#include
int main(int, char**)
{
printf("Hello, C++");
return 0;
}
编译,执行, 一气呵成, 哇, 有输出了啊
面向对象:
标准输出有两个, 一个是正常输出, 一个是错误输出, 分别对应
std::cout 和std::cerr
包含头文件
#include
引入命名空间std, 然后使用
using namespace std;
当然也可以不在全局引入命名空间std
虽然你可以使用using的方式引入整个命名空间, 但是个人建议最好别这么干?
为什么呢?
你想啊, 要是你写了一个跟标准库里面你还没用过的同样名字的函数, 你该怎么使用?
你要真想偷点懒啊, 你改成
// using namespace std;
using std::cout;
这样你就之引入了std::cout这一个对象了, 其他的就不收受影响了
我建议啊, 你最好直接使用 std::cout, 虽然多写了一些代码, 但是这样写好处更多啊, 比如不用担心自己写的函数和标准库同名, 多个命名空间都在使用时, 可以很清楚的知道使用的时哪个命名空间里的了
那试试:
#include
int main(int, char **)
{
std::cout << "Hello, C++" << std::endl;
return 0;
}
和std::cout一样, 标准库中的一个对象, 区别是功能不一样
什么功能呀?
换行 + 刷新缓冲区, 相当于 \n + std::flush
std::flush是啥?
也是一个对象啊, 用来刷新缓冲区
$ g++ main.cc -o main
$ ./main
Hello, C++
哈哈,终于有自己写的输出文本了
#include
int main(int, char**)
{
int sum = 1 + 2;
std::cout << sum << std::endl;
return 0;
}
$ g++ main.cc -o add
$ ./add
3
#include
int main(int, char**)
{
int sum = 10 - 5;
std::cout << sum << std::endl;
return 0;
}
$ g++ main.cc -o minus
$ ./minus
5
#include
int main(int, char**)
{
int a = 4 * 8;
std::cout << a << std::endl;
return 0;
}
$ g++ main.cc -o times
$ ./times
32
#include
int main(int, char**)
{
int a = 10 / 2;
std::cout << a << std::endl;
return 0;
}
$ g++ main.cc -o divide
$ ./divide
5
#include
int main(int, char**)
{
int a = 11 + 2 * 6 - 24 / 6;
std::cout << a << std::endl;
return 0;
}
$ g++ main.cc -o main
$ ./main
19
#include
int main(int, char**)
{
int a = (1 + 2) * (9 - 4) - (4 + 23) / 3;
std::cout << a << std::endl;
return 0;
}
$ g++ main.cc -o main
$ ./main
6
被除数 / 除数 = 商 + 余数, 商保留, 余数不要了
用浮点数呗, 就是数学意义上的实数, float, double
#include
int main(int, char **)
{
float a = 13.5f / 3;
std::cout << a << std::endl;
double b = 25.25 * 10;
std::cout << b << endl;
return 0;
}
$ g++ main.cc -o main
$ ./main
4.5
252.5
从含义上讲没区别, 区别就在这两个类型占用内存大小不一样,所以表示的实数精度也不一样, float 有32位二进制, double 有64位二进制, 二进制位数越多, 能表示的数越多, 精度也越高
整型
(unsigned) char -> 8位, 1字节
(unsigned) int -> 32位, 4字节
(unsigned) short -> 16位, 2字节
(unsigned) long -> 跟编译器有关 不低于32位, 不高于64位
(unsigned) long long -> 64位, 8字节
浮点型
float double
布尔型 bool -> 表示真或假, 只有两个值 true: 表示真, false: 表示假
字符型
char, (unsigned ) char -> char 一般表示ASCII字符, 表示我们在键盘上所有能看到的符号(英文,数字,各种标点符号)的二进制表示
unsigned表示没有正负, signed表示有正负, 不写的情况下, 默认用的时signed
当然可以了, 分为隐式转换(自动转换)和显示转换(强制转换)
隐式转换(自动转换):
转布尔型
0: false, 非0: true
转整型
有符号同字节数类型转无符号类型, 如 int -> unsigned int
较小字节数转较大字节数同符号性类型, 如 short -> int
浮点型转整形, 小数位舍去, 溢出位舍去 如 (float) 355.5f -> (unsigned char) 99
转浮点型
整数转浮点
使用数组
如:
int array[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
取出值:
int a = array[5]; // 常用方式 取出数组array的第6个值, 序号永远从0开始表示第一个
int b = *(array + 2); // 指针方式取出array的第3个值(高级用法, 指针部分详解)
修改值:
数组名[序号] = 某个值
array[7] = 70; // 修改数组array的第8个数为70
*(array + 6) = 66; // 修改array的第7个数为66(高级用法, 指针部分详解)
int An[3] = {1, 2, 3}; //序号从0 ~ 2
double Bn[] = {1.0, 1.1, 1.2, 1.3}; //自动识别出个数4, 序号从0 ~ 3
前面用了一个printf函数用来打印, 但是打印的时候都要用\n才能换行, 我想自己写一个函数,能自动换行, 可以不?
当然可以
void my_printf(??);
我要输入文本做参数怎么写参数啊?
文本其实就是多个字符组成的字符数组啊, 只不过系统系统为我们增加了一个结束字符 ‘\0’, 也就是二进制的0, 这个值不代表任何字符, 所以用来当结束标记正好
"Hello, C++"这段文本怎么表示啊
const char name[11]; // 为啥 11?
H e l l o , 空格 C + + \0
正好十一个
const 是干嘛的?
修饰 name这个字符型数组内容不能改呀
试试就知道什么意思啦
"Hello, C++" [6] = 'A'; //编译报错
const char name[11];
name[2] = 'B'; // 表一报错啊
要是需要修改呢?
那就别用const 修饰好呗
char hello[11] = "Hello, C++";
hello[0] = 'h'; //编译通过, hello 的文本内容变成了 "hello, C++";
void my_printf(const char text[]);
void my_printf(const char text[])
{
printf(text);
printf("\n");
}
试试看
#include
void my_printf(const char text[]);
int main(int,char**)
{
my_printf("Hello");
my_printf("C++");
return 0;
}
void my_printf(const char text[])
{
printf(text);
printf("\n");
}
$ g++ main.cc -o main
$ ./main
Hello
C++
我有两个数, 都是int , 现在我要交换这两个数的值怎么做? 我这样为什么不行啊?
void swap(int a, int b)
{
int temp = a;
a = b;
b = temp;
}
//...
int a = 5;
int b = 6;
swap(a, b);
// 怎么a和b没交换成功啊
在C++的函数参数中, 都是以值的方式进行传递的, 上面写的参数地的都是a 和 b的值, 也就是把这两个数的值做了一下拷贝到函数内, 函数内无论怎么修改都是修改拷贝出来的值, 所以才无法真正交换呀
哦哦, 那怎么才能交换啊
我两个篮子里分别放了1个苹果和1个桃儿, 现在然你交换,我应该把什么给你你才能交换呢?
A. 苹果和桃儿的照片
B. 两个篮子
那肯定是篮子啊
同样的道理
a 和 b分别存了5 和 6, 要交换a 和 b的两个值, 那肯定就得把a 和 b的内存位置通过参数传给函数嘛, 然后函数里面通过直接操作内存内容交换不就把a 和 b交换过来了嘛
那怎么知道a和b的内存位置啊?
取内存地址呗, &符号了解一下, biu的一下就把内存地址取出来了
地址 ad = &a;
地址怎么表示啊?
你取出来的是什么类型变量的地址呀
a是int 类型, int 类型的地址什么类型啊
int * 表示int 地址类型, 我们称它int指针类型, 你要喜欢叫地址类型还是指针类型都随你咯
哦哦, 那是不是这样表示
int * ad = &a;
或者这样
int *ad;
ad = &a;
很聪明, 两种都可以
哦哦, 那我可不可以偷懒一点一次把地址类型都定义好
像这样
int* ad,bd;
你这不行啊,你这分明是定义一个int *ad和一个int bd嘛
啊? 我把*写的离int 近一些都不行吗?
不行不行, 你这一行里有几个*才能表示几个指针啊, 再懒也不能一个*表示多个指针啊
你要真想偷懒, 你可以把int *这个指针类型重新起个名字
怎么起啊?
typedef 或者using, 看你喜欢了
typedef int * intptr;
using int_pointer = int *;
哦哦, 这么神奇啊, 也就是说, 如果 直接用指针类型定义变量, 一行里面要定义几个指针就必须几个*对吧, 不加*的就是原始类型不是指针类型了
int *a, *b;
那为了用*表示一个指针, 我还是把 *靠近指针变量名比较好, 这样不会看错
指针定义了, 地址也取好了, 怎么把地址的值取出来啊
用*啊
int *ad = &a;
*ad = 10; // 把ad指针指向的内存内容改成10
@_@晕啊, 怎么也是用*啊
你这么理解: 定义的时候, *用来定义指针, 使用的时候*用来取指针指向内存的内容,&符号呢,你就用来取地址好了
那我可不可以取完地址直接用*来赋值啊
像这样
int a = 100;
*(&a) = 101;
完全可以啊, 而且还经常用
哦哦, 那我知道交换怎么写了
void swap(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
int a = 10;
int b = 20;
int *ad = &a;
int *bd = &b;
swap(ad, bd);
// 或者直接不用中间的指针变量了
swap(&a, &b);
除了使用变量本身, 我还可以直接操作标量的内存吗?
可以呀, 你用引用给变量起个新名字就好了
int a = 100;
int& a_a = a;
a_a = 101; // a也变成了101
用别名去访问也能修改内存内容
但是, 取别名的时候要注意了, 定义的时候就得告诉这个别名到底是谁的
int a = 100;
int& aa; // 错误, 必须起名的同时指定是谁的别名
aa = a;
别名又叫引用, 定义应用的时候, 必须有原始变量来初始化, 不然不知道给谁其别名了
引用也可以做参数呢, 既然是参数, 那就说明不确定是谁的别名了, 传进来的是谁, 那就是谁的别名(所以就没有必要初始化了), 哈哈,够任性吧
void change(int &a, int new_value)
{
a = new_value;
}
int a = 100;
change(a, 102); // a = 102;
那是不是前面的交换也可以用引用来实现, 比如这样
void swap(int& a, int& b)
{
int temp = a;
a = b;
b = temp;
}
机智如你, 还能举一反三了, 不错不错
好纠结啊, 我想用一个变量表示水果, 可是水果就只有目前的几种, 苹果, 梨, 桃儿, 香蕉, 可是我要是用整数表示改用哪些呢?
而且我明明上面用了0表示苹果, 写到下面的时候又给忘了, 还记错成了2,有没有好的解决办法啊
enum fruit {
apple, orange, banana, peach, pear
};
fruit one = apple;
这总记得住吧
嗯嗯, 记得住, 可是这些名字都用的什么数啊?
你给枚举定义的时候什么数都不写,那就从0开始, 依次递增, 你写了, 那就按你写的来, 后面没写的就从你写的那个值的下一个开始依次递增
比如上面的 apple = 0, orange = 1, banana = 2, peach = 3, pear = 4
但是如果你改成
enum fruit {
apple, orange = 3, banana, peach = 1, pear
};
那 apple = 0, orange = 3, banana = 4, peach = 1, pear = 2 了
老师让我统计学生信息, 我都再Excel表格了, 可是每个学生信息都好多啊
姓名, 学号, 性别, 班级, 年龄等等, 我用一个变量没法表示一个学生啊
enum Gender {
male, female
};
struct Student
{
char name[16];
int number;
enum Gender gender;
int age;
// ...
};
Student xiaoming;
怎么分别修改学生的信息啊, 比如年龄, 去年到今年, 年龄都得+1岁
.操作符啊, 你可以理解为 “的”
比如
xiaoming.age = xiaoming.age + 1; // 小明的年龄+1岁
你要是懒, 还能写成
xiaoming.age++;// 或者 ++xiaoming.age;
区别嘛,单独使用几乎没啥区别, 如果是类似这种
int age = xiaoming.age++;
// 和 int age = ++xiaoming.age;
你这么理解
int age = xiaoming.age++:
int age = xiaoming.age; xiaoming.age = xiaoming.age + 1;
int age = ++xiaoming.age:
xiaoming.age = xiaoming.age + 1; int age = xiaoming.age;
哦哦, ++放在前面就是先+1再把+1后的值拿来用, ++放在后面就是先把值拿来用, 用完了再把原来的值+1, 对吧
孺子可教也