C++ 小白 学习记录--3

c++博大精深, 越看越觉得不会的太多. 回炉一下吧~ 大神们 请勿浪费时间~

第三章

1. using

跟c#类似 如std::cin   使用using ,  using std::cin 后 程序中直接使用cin即可.

每个声明只能引入空间中的一个成员, 不能像C# 那样使用*

头文件中不应用using

2. string

无论是直接=赋值还是使用 string s("123123") string s2(s) 都是赋值, 而不是引用, 新变量都是保存的副本.  string s3 (n, 'c') 使用n个c初始化s3,  = 拷贝初始化, 而使用() 是直接初始化.

string的一些操作

C++ 小白 学习记录--3_第1张图片

s.emtpy()  为啥不搞个s.isEmtpy() 多明显呢!!

需要注意的是s.size() 返回的是一个string::size_type 类型, 本质是一个无符号的类型的值, 为了机器无关性, 设计的一个类型. 尤其需要注意的是, 如果是 s.size() < n, n如果是负值, 则刚才的判断几乎肯定是true, 因为n在参与无符号运算时会自动转换为无符号值, 此时n会很大!

字符大小比较: 如果大小写都相同长度不同, 长的>短的

如果字符都不相同, 则比较的是第一对相同位置上的字符大小

如 string str1="hello", str2="hi"; 则 str2>str1 

+, += 字符串连接, 必须确保符号两边至少有一个对象是string

string str= "123" + "aaa";  //此处+ 不是字符串连接

请注意一下两者的区别:

  string str1 = "123"

  string str2 = str1 + "111" + " 222 ";  // √  第一个+ 会产生一个string, 然后 和第二个+运算 都符合要求

  string str3 = " 111 " + "222" + str1; // ×  第一个不能产生string, 所以错误

判断字符类型

C++ 小白 学习记录--3_第2张图片

这些函数为啥不能使用isSpace(c) 的形式呢, 看着都费劲!

如何处理 每个字符?

    string str("hello world c++");
    for (auto a : str) std::cout << " a in str :" << a; // 遍历 读取
    for (auto& a : str) { // 遍历 修改
        a = std::toupper(a);
    }

    for (auto a : str) {
        auto* b = &a; // 通过指针的方式 修改str中的值, 比较二的但能实现目的
        *b = std::toupper(a);
    }

 或者使用下标 修改. str[x] = xx; 其下标类型为string::size_type 或者能转化为该类型的类型

vector 容器 像list

#include

using std::vector;

vector 不能包含引用, 因为引用不是对象

初始化方法

如果提供的是初始元素值的列表, 只能把初始值放在{}中

vector v1 // 初始化一个空的

vector v2(v1)  = (vectorv2=v1)用v1个初始化v2

vectorv3(n,val) n 个val初始化v3

vectorv4(n) n个空值

vectorv5{a,b,c...} =(vectorv6={a, b, c...})

如果提供的值不能跟要求的类型相符, 则会尝试初始化n个默认值, 如

vector v1 {10}, 则会初始化10个string默认值的vector

vector 的操作

如果循环体内包含添加动作, 则不能用范围for循环?? 会引起for循环判断失效???

C++ 小白 学习记录--3_第3张图片

注意函数size 的返回值类型是 vector::size_type, 必须包含T, 如vector::size_type, 而vector::size_type 则是错误的定义

如果内部元素不能比较大小, 则vector也不能比较大小

迭代器iterator

迭代器跟指针很像, 但是跟指针又有很多不同, 迭代器的运算是指自己向前/后移动, 指针则是地址.

迭代器中的end, 并不是指向最后一个元素,而是指向最后一个元素的下一个位置, 其不能++或--

*iter 返回迭代器iter所指元素的引用

iter->xx 解引用iter并获取元素的名为xx的成员

如果对象为空, 则其begin和end迭代器相同

为何C++的for循环中不常用<, <=, >, >= 判断结束, 是因为c++标准库中容器的迭代器 都实现了!=和==, 所以不能用上面的判断,而是用!=判断 怪不得看的难受

vector::iterator it; 和vector::const_iterator it2 的区别

begin end cbegin cend 后面两个只返回const_iterator

凡是使用了迭代器的循环体, 都不要试图修改迭代器所属容器的大小.

数组

数组的大小固定, 灵活性不如vector, 性能优于vector

数组的维度必须是常量. int *parr[10]; 含有10个整型指针的数组,而不是指向含有10个元素的数组的指针

C++ 小白 学习记录--3_第4张图片

int (*p)[10] = &arr;  p 指针, 指向一个10个元素的数组

int (&arrRef)[10] = arr; arrRef 引用, arr的别名

注意使用字符串字面值初始化字符数组时的'\0' 问题, 该空字符会占用一个位置

不能使用数组初始化另一个数组

不能把一个数组直接赋值给另一个数组

数组的下标类型是size_t 机器相关的无符号类型.

使用数组的名字时, 编译器会自动讲数组名替换为指向数组第一个元素的指针,特性

如string *p2 =nums, 等价于string *p2 = &nums[0]

auto 推断数组时 得到是指针, 而decltype 则会推断出真正的类型

数组的指针 也是 迭代器

尾后指针 = &arr[数组长度]  或者使用end函数 (begin用于获取首指针)

尾后指针 因为指向的是一个不存在的对象, 所以不能解引用和递增

数组的指针也可以进行下标运算, 如

int arr[2]={1, 2}

int *p=arr,  而 p[1] 等价于*(p+1) 等于arr[1], 还可以是负数如 p[-2]

慎用 负数, 如果负数超出范围 编译器 不报错, 但是其指向的数据 不知道是什么

c中的几个函数

strlen 返回p的长度, 空字符不计算在内, 如果传入的是指针, 指针指向的对象如果没有'\0' 则会发生严重错误

strcmp(p1, p2) 比较p1和p2的相等性, p1==p2 return 0, p1>p2 return 正, 反之 返回负

strcat(p1, p2)  p2 附加到p1, 返回p1

strcpy(p1,p2) 将p2 拷贝给p1 , 返回p1

尽量使用标准库string, 不要使用c风格字符串, c风格字符串不安全且低效.

为了兼容 允许使用以空字符结束的字符数组初始化string或赋值, string 加法运算中也可以出现一个以空字符结束的字符数组.

string 转 cha* 需要使用string的c_str(), 结果为const char*

字符数组可以初始化vectory 如 vector ivec(begin(int_arr), end(int_arr)) , 反之则不行. 此种初始化方法, 不包含end(int_arr)所指向的元素.

多维数组

int ia[3][4] = {{0,1,2,3}...} = {0,1,2,3,...} 内层{}不是必须的, 但是还是带上清晰明了.

如果只初始化每行首元素

int ia[3][4] = {{0],{4}, {8}}  {}不能省略.

注意这种引用定义

int (&row)[4] = ia[1],   row绑定到ia的第二行上.

在多维数组使用范围for遍历时需要使用引用, 否则 会被自动转化为指针.

如何理解int * p[4] 和int (*p)[4]

int * p[4]  可以参照 vs2019中的默认格式,把int* 作为一个整体即 (int*) p[4] ,理解时等同于int p[4], 就可以理解为一个数组,里面存放了4个整型指针.

int (*p)[4]  = int a [4],   a=*p p 是一个指针, 该指针指向一个4个整数的数组. 

可以使用using 或者typedef 定义别名,  个人不建议, 感觉更乱.

如 using int_arry = int[4]   或者 typedef int int_array[4]

一个练习题: 输出数组ia的元素, 方法1 使用for语句管理迭代过程, 方法2 使用下标, 方法3 使用指针, 方法4 auto

  

	int ia[3][4] = {
		{0,1,2,3},
		{4, 5, 6, 7},
		{8, 9, 10, 11}
	};
//方法1
    for (int (&row)[4] : ia) {
		for (int &col : row) {
			std::cout << col;
		}
		std::cout << std::endl;
	}
//方法2
    size_t row = 0;
	size_t col = 0;
	for (row = 0; row < 3; ++row) {
		for(col=0; col<4 ; ++col) std::cout << ia[row][col];
		std::cout << std::endl;
	}
//方法3
    for (int (*p)[4] = std::begin(ia); p != std::end(ia); ++p) {
		for(int *p2 = *p; p2 != std::end(*p); ++p2) std::cout << *p2;
		std::cout << std::endl;
	}
//方法4
	for (auto& row : ia) {
		for (int& col : row) std::cout << col;
		std::cout << std::endl;
	}

 

 

你可能感兴趣的:(c++学习,c++)