Chapter 4 复合类型
1)数组的复习:¶
(1)只有定义数组的时候才可以初始化,此后就不可以使用了; 不能将一个array赋给另一个array!
(2)初始化数组,提供值可以少于数组元素个数 这种针对数组部分初始化的行为,编译器自动将其他元素补成 0 【不在乎数组定义在main()的内/外】
C++ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 211) 写法一:[在函数体外面] # include<iostream> using namespace std; int a[10]={1,1}; int main() { for(int i=0;i<=9;i++) cout << a[i] <<' '; return 0; } 2) 写法二:[在函数体内部] # include<iostream> using namespace std; int main() { int a[10]={1,1}; for(int i=0;i<=9;i++) cout << a[i] <<' '; return 0; } 结果都是: 1 1 0 0 0 0 0 0 0 0
(3)数组元素全部赋值成0: int a[100] = { 0 }; reason: 显式地将第一个元素设置为0,其余元素编译器按(2)中规则自动赋值为0 ps:该写法等价于 int a[100] = { }; [ 括号内置为空 ] tips:int a[100] = {1}; 含义是 第一个元素 a[0] 是1,其余元素都是0
(4)初始化时[ ]写法,编译器将自动计算元素个数: int ar[ ] = {1,2,3,99}; // 自动计算出num=4
C++ 1 2 3 4 5 6 7 8 9 10 11#include<iostream> using namespace std; int main() { int a[] = {1,4,3,6,5,8,0}; int num = sizeof(a)/sizeof(int); cout << num <<endl; return 0; } 结果: 7
2) 字符串(char):¶
(1)char 的字符数组与字符串: 字符数组:char dog[8] = {'a','b','c','d','e','f','g','r'}; // not a string 字符串: char cat[8] = {'a','b','c','d','e','f','g', '\0' }; // is a string
[1] 打印cat时,打印到'\0'空字符就结束,因此只显示abcdefg [2] 打印dog时,打印完字符数组元素后,接着打印出内存中的‘随后字符’,直到遇见'\0'为止 由于空字符'\0'在内存中非常常见,因此此过程很快就停止!
C++ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15#include<iostream> using namespace std; int main() { char cat[8] = {'a','b','c','d','e','f','g', '\0' }; // is a string cout << cat <<'\n'; char dog[8] = {'a','b','c','d','e','f','g','r'}; // not a string cout << dog <<'\n'; return 0; } 结果: abcdefg abcdefgrabcdefg
(2)对于字符串的写法改进:
ps: “ ” 与 ’ ‘不能互换!
C++ 1 2char bio[11] = "mr. cheeps"; // 10个元素 + 1个'\0' char fish[] = "dujkadfukasgbdf" // 编译器自动计算元素个数
(3)字符串拼接时,不会在被连接的str之间自动添加空格,后者紧跟前者
(4)字符串部分初始化后,其余元素自动赋值为'\0' :
C++ 1 2 3 4 5 6 7 8 9 10 11#include<iostream> using namespace std; int main() { char cat[8] = {'a','b','c','d'}; // is a string cout << cat <<'\n'; return 0; } 结果: abcd
(5)strlen() 与 sizeof() 区别:
sizeof( ) : 整个数组的长度 [ 取决于开设状态 ] strlen( ) : 存储在数组中的字符串的长度 [ 取决于有效元素个数 ]
C++ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36// strings.cpp -- storing strings in an array #include <iostream> #include <cstring> // for the strlen() function int main() { using namespace std; const int Size = 15; char name1[Size]; // empty array char name2[Size] = "C++owboy"; // initialized array // NOTE: some implementations may require the static keyword // to initialize the array name2 cout << "Howdy! I'm " << name2; cout << "! What's your name?\n"; cin >> name1; cout << "Well, " << name1 << ", your name has "; cout << strlen(name1) << " letters and is stored\n"; cout << "in an array of " << sizeof(name1) << " bytes.\n"; cout << "Your initial is " << name1[0] << ".\n"; name2[3] = '\0'; // set to null character cout << "Here are the first 3 characters of my name: "; cout << name2 << endl; // cin.get(); // cin.get(); return 0; } 结果: Howdy! I'm C++owboy! What's your name? hbx Well, hbx, your name has 3 letters and is stored in an array of 15 bytes. Your initial is h. Here are the first 3 characters of my name: C++
(6)字符串输入:
【1】引入:
发现问题: 我们都没有机会输入dessert,程序便将它显示出来,并且终止程序了,显而易见: 想输出的dessert变成了这个人的姓氏,实际上输出的人名也是他的first name
C++ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27// instr1.cpp -- reading more than one string #include <iostream> int main() { using namespace std; const int ArSize = 20; char name[ArSize]; char dessert[ArSize]; cout << "Enter your name:\n"; cin >> name; cout << "Enter your favorite dessert:\n"; cin >> dessert; cout << "I have some delicious " << dessert; cout << " for you, " << name << ".\n"; // cin.get(); // cin.get(); return 0; } 结果: Enter your name: Alistair Dreeb Enter your favorite dessert: I have some delicious Dreeb for you, Alistair.
分析问题:
1)cin使用 空白(空格,制表符,换行符)作为 str 结束的终止位置 2)这就意味着:cin只能获取第一个单词 3)本例中:cin 将Alistair作为第一个字符串,并将其放置于name数组中;因此Dreeb留在输入队列中;当cin在输入队列中搜索dessert时,首先看到的是Dreeb;因此cin读取的是Dreeb,并将其放置于dessert数组中
解决问题: 对于 New York 、Harvard University等短语,我们需要的是面向行而不是面向单词的方法 => 使用getline() 与 get() 这两者都读取一行输入,直到到达换行符'\n',随后getline()将换行符替换成'\0'【等价于丢弃换行符】,而get()将换行符保留在输入序列中!
【2】getline(): ![[Pasted image 20230726161716.png]] 格式:cin.getline(arr_name , max_num) 机理:getline每次读取一行,它通过换行符确定行尾,但是不保存它;在存储字符串时,它将空字符’ \0 ‘代替换行符!
![[Pasted image 20230726162058.png]]
【3】get(): ![[Pasted image 20230726163507.png]] 格式:cin.get(arr_name , max_size) ps【解释上述code】
(1) cin.get(name,Arsize); // 输入name,末尾带上一个'\n' (2) cin.get(); // 吞掉前面遗留的'\n'(自己本身不含有'\n') (3) cin.get(dessert,Arsize); // 输入dessert,末尾带上一个'\n'
【4】混合输入数字与str导致的问题:
problem:我们根本没有输入addresss的机会 analysis:cin读取年份后,将回车键生成的换行符'\n'留在了输入队列中,后面cin.getline(...)看见换行符,认为这是一个空行,并将一个空串赋给address数组 solve:在读取add之前先丢弃换行符'\n'
C++ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29// numstr.cpp -- following number input with line input #include <iostream> int main() { using namespace std; cout << "What year was your house built?\n"; int year; cin >> year; // cin.get(); cout << "What is its street address?\n"; char address[80]; cin.getline(address, 80); cout << "Year built: " << year << endl; cout << "Address: " << address << endl; cout << "Done!\n"; // cin.get(); return 0; } 结果: What year was your house built? 2004 What is its street address? Year built: 2004 Address: Done!
C++ 1 2 3 4 5 6 7 8 9 10 11 12cin >> year; cin.get() ... 结果: What year was your house built? 2004 What is its street address? hf Year built: 2004 Address: hf Done!
3) 字符串(string):¶
(1)初始化,赋值,拼接,附加... 过于简单,略之! (2)输入/输出: 面向单词:cin、cout 面向行:getline(cin , str)
C++ | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
|
4) 结构体:¶
基础部分省略,这里着重介绍程序分析:
C++ | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
C++ | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
5) 共用体:¶
共用体(union)能够存储不同的数据类型,但是只能同时存储其中的一种类型 exp:(1)struct能同时存储int、char、double ; (2)union存储int/char/double eg:
C++ | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
6) 枚举:¶
enum工具:创建符号常量,可以代替const 评价:限制严格,范围狭小,不太好用!
设置枚举值的规则: (1)指定值必须是整数:int / long / long long
C++ | |
---|---|
1 |
|
C++ | |
---|---|
1 2 |
|
7) 指针和自由存储空间:¶
(1)指针是一个变量,其存储的是值的地址,而不是值本身 (2)这种存储数据的策略是:将地址视为指定量,而将值视为派生量 (3)运算符* 是”间接值“,也叫作:解引用
参考代码:
C++ | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
(4)声明和初始化指针:
【1】初始声明:
![[Pasted image 20230726214115.png]]
tips:对于每个指针变量名,都需要使用一个*
C++ 1 2 3int* p1 , p2; // 创建的是指针p1 和 int型p2 reason[系统自动识别过程]: int ——— *p1 ——— p2
【2】示例展示:
C++ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15// init_ptr.cpp -- initialize a pointer #include <iostream> int main() { using namespace std; int higgens = 5; int * pt = &higgens; // 被初始化的是指针pt,而不是它指向的值! cout << "Value of higgens = " << higgens << "; Address of higgens = " << &higgens << endl; cout << "Value of *pt = " << *pt << "; Value of pt = " << pt << endl; // cin.get(); return 0; }
(5)使用new来分配内存:
通用格式:typename * pointer_name = new typename; eg: int *i = new int ; ![[Pasted image 20230726214237.png]]
示例:
ps:sizeof( p ) 与 sizeof( *p ) 的区别: 深入理解计算机各种类型大小(sizeof) - DoubleLi - 博客园 (cnblogs.com)
C++ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35// use_new.cpp -- using the new operator #include <iostream> using namespace std; int main() { int nights = 1001; int * pt = new int; // allocate space for an int *pt = 1001; // store a value there cout << "nights value = "; cout << nights << ": location " << &nights << endl; cout << "int "; cout << "value = " << *pt << ": location = " << pt << endl; double * pd = new double; // allocate space for a double *pd = 10000001.0; // store a double there cout << "double "; cout << "value = " << *pd << ": location = " << pd << endl; cout << "location of pointer pd: " << &pd << endl; cout << "size of pt = " << sizeof(pt); cout << ": size of *pt = " << sizeof(*pt) << endl; cout << "size of pd = " << sizeof pd; cout << ": size of *pd = " << sizeof(*pd) << endl; // cin.get(); return 0; } 结果: nights value = 1001: location 0x61fe14 int value = 1001: location = 0xfd1640 double value = 1e+07: location = 0xfd1660 location of pointer pd: 0x61fe08 size of pt = 8: size of *pt = 4 size of pd = 8: size of *pd = 8
(6)使用delete来释放内存:
它将在使用完内存后,将其归还给内存池;归还/释放的内存可供程序的其他部分使用
C++ 1 2 3 4 5 6int *ps = new int; ...... delete ps; !!!这将释放ps指向的内存,但不会删除指针ps本身!!! 例如:可以将ps重新指向另一个新分配的内存块
1)注意new与delete的严格配对! 2)不要创建两个指向同一个内存块的指针,因为这样极大可能产生"double free"错误!
(7)使用new来创建并使用动态数组:
[1] 通用格式:typename * pointer_name = new typename [ num ] ;
[2] 创建: ![[Pasted image 20230726213109.png]] [3] 使用: ![[Pasted image 20230726213452.png]] [4]示例:要注意指针+/-的含义
![[Pasted image 20230726213922.png]]
C++ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25// arraynew.cpp -- using the new operator for arrays #include <iostream> int main() { using namespace std; double * p3 = new double [3]; // space for 3 doubles p3[0] = 0.2; // treat p3 like an array name p3[1] = 0.5; p3[2] = 0.8; cout << "p3[1] is " << p3[1] << ".\n"; p3 = p3 + 1; // increment the pointer cout << "Now p3[0] is " << p3[0] << " and "; cout << "p3[1] is " << p3[1] << ".\n"; p3 = p3 - 1; // point back to beginning delete [] p3; // free the memory // cin.get(); return 0; } 结果: p3[1] is 0.5. Now p3[0] is 0.5 and p3[1] is 0.8.
[5]指针小结: ![[Pasted image 20230726215756.png]] ![[Pasted image 20230726215816.png]]
8) 指针、数组、指针运算:¶
(1)指针与字符串: ![[Pasted image 20230726220411.png]] char 数组名、char指针、"str......"都被解释为:str第一个字符的地址
C++ | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
|
**程序说明: 1)一般来说,给cout提供一个指针,它将打印地址 2)但是如果指针类型是 char ,则cout将显示指向的字符串 [识别它为数组名] 3)如果要显示字符串地址,必须进行强制转换!eg: (int) ps 4)将animal赋给ps只是复制地址,这两个指针指向相同的内存单元[装有str];而不是复制字符串
字符串函数strcpy(... , ... , ...) 的使用简介: ![[Pasted image 20230726222806.png]] ![[Pasted image 20230726222938.png]]
(2)使用new创建动态结构: 访问方法:
1)p->member ![[Pasted image 20230726223453.png]] 2)(*p).member
![[Pasted image 20230726223610.png]]
C++ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31// newstrct.cpp -- using new with a structure #include <iostream> using namespace std; struct inflatable { // structure definition char name[20]; float volume; double price; }; int main() { inflatable * ps = new inflatable; // allot memory for structure cout << "Enter name of inflatable item: "; cin.get(ps->name, 20); // method 1 for member access cout << "Enter volume in cubic feet: "; cin >> (*ps).volume; // method 2 for member access cout << "Enter price: $"; cin >> ps->price; cout << "Name: " << (*ps).name << endl; // method 2 cout << "Volume: " << ps->volume << " cubic feet\n"; // method 1 cout << "Price: $" << ps->price << endl; // method 1 delete ps; // free memory used by structure // cin.get(); // cin.get(); return 0; }
9)类型组合实践:¶
C++ | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
|