C++基础第三弹
-
- 7.C++数组
- 8.C++字符串
-
- 8.1C风格字符串
- 8.2C++中的string类
- 8.3输入字符串
-
- [8.3.1cin >>](#8.3.1cin >>)
- [8.3.2cin.get >>](#8.3.2cin.get >>)
- 8.3.3cin.getline();
- 8.3.4getline();
- 8.3.5gets();
- 8.3.6getchar();
- 8.3.7原始打印R"(str)"
- 9.C++指针
- 10.C++引用
7.C++数组
- 数组可以存储一个固定大小的相同类型元素的顺序集合,数组就是用来存储一系列数据,往往是一系列相同类型的变量
7.1声明数组
- 语法:
数据类型 数组名[数组长度]
- 数组长度必须是大于0的整数常量
7.2初始化数组
7.2.1固定大小数组
c++
//创建包含5个整数的数组
int myArray[5];
7.2.2初始化固定大小数组
c++
//根据初始化列表推断数组大小
int myArray[]={1,2,3,4,5};
7.2.3指定大小并初始化数组
c++
//创建并初始化数组,未初始化的元素,默认初始化为0
int myArray[5]={1,2,3};
7.2.4动态数组
c++
//使用指针和动态内存分配来创建数组,大小在运行时确定
int *myArray = new int[10];
7.2.5标准库容器std::array
c++
//std::array是固定大小的数组模板类,
std::array <int,5> myArray;
7.2.6标准库容器std::vector
c++
//创建动态数组(向量)
std::vector<int> myVector;
//调整向量的大小
myVector.resize(5);
7.3访问数组元素
-
获取数组的元素个数:
sizeof(arr) / sizeof(arr[0])
-
整个数组所占内存空间:
sizeof(arr)
-
每个元素所占内存空间:
sizeof(arr[0])
-
通过数组名查看数组首地址:
(int)arr
-
查看数组种第一个元素的地址:
(int) &arr[0]
-
通过数组名称加索引进行访问,元素的索引放在方括号内,跟在数组名称的后边
c++#include <iostream> using namespace std; #include <iomanip> using std::setw; int main () { int n[ 10 ]; // n 是一个包含 10 个整数的数组 // 初始化数组元素 for ( int i = 0; i < 10; i++ ) { n[ i ] = i + 100; // 设置元素 i 为 i + 100 } cout << "Element" << setw( 13 ) << "Value" << endl; // 输出数组中每个元素的值 for ( int j = 0; j < 10; j++ ) { cout << setw( 7 )<< j << setw( 13 ) << n[ j ] << endl; } return 0; }
7.4C++数组详解
概念 | 描述 |
---|---|
多维数组 | C++ 支持多维数组。多维数组最简单的形式是二维数组。 |
指向数组的指针 | 可以通过指定不带索引的数组名称来生成一个指向数组中第一个元素的指针。 |
传递数组给函数 | 可以通过指定不带索引的数组名称来给函数传递一个指向数组的指针。 |
从函数返回数组 | C++ 允许从函数返回数组。 |
7.5C++多维数组
- 语法:
数据类型 数组名[长度1][长度2]...[长度N]
7.5.1二维数组
- 语法:
数据类型 数组名[长度X][长度Y]
- 标识数组中的某个元素,比如
array[X][Y]
来确定唯一元素
7.5.2初始化二维数组
-
固定大小数组
c++int arr[3][3]={};
-
初始化固定大小数组
c++int arr[3][3] ={ {1,2,3}, {4,5,6}, {7,8,9} };
-
行数初始化数组,元素个数确定列数
c++int [][3]={ {1,2,3}, {4,5,6} }; //等同于 int [2][3]={ {1,2,3}, {4,5,6} };
-
不指定大小初始化数组
c++int arr[]={ {1,2,3}, {4,5,6} };
-
动态分配二维数组
c++int **arr = new int*[3]; for(int i=0;i<3;i++){ arr[i] = new int[3]; } //手动释放内存 for(int i=0;i<3;i++){ delete[] arr[i]; } delete [] arr;
-
使用std::vector初始化数组
c++std::vector <std::vector<int>> vec; //创建一个3✖3的二维数组 vec.resize(3,std::vector<int>(3,0));
-
使用std::array初始化数组
c++//创建一个3✖3的二维数组 std::array<std::array<int,3>,3> arr;
-
指针数组初始化
c++int arr[3][3] = { {1,2,3}, {4,5,6}, {7,8,9} }; //创建指向二维数组的指针 int (*ptrArr)[3] = arr;
7.5.3访问二维数组元素(3种)
c++
//
// Created by 16690 on 2024/4/19.
//
#include <iostream>
#include <vector>
using namespace std;
int main(void) {
int arr[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// 遍历二维数组
for (int i = 0; i < 3; ++i) { // 外循环控制行
for (int j = 0; j < 3; ++j) { // 内循环控制列
std::cout << arr[i][j] << " "; // 访问并打印数组元素
}
std::cout << std::endl; // 每行结束后换行
}
//范围for循环遍历二维数组
for (const auto &row: arr) {
for (const auto &elem: row) {
cout << elem << " ";
}
cout << endl;
}
//使用指针遍历二维数组
int (*ptr)[3]= arr;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
cout<<ptr[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
7.6指向数组的指针
-
数组名是指向数组中第一个元素的常量指针
c++//声明一个数组 double myArray[10]; //myArray是一个指向&myArray[0]的指针,即数组myArray的第一个元素地址 double *p; p=myArray; cout<<"p: "<<*p<<endl;
-
将第一个元素的地址存储在p中,就可以使用
*p、*(p+1)、*p(p+2)
等来访问数组元素
7.7传递数组给函数
- 通过指定不带索引的数组名来传递一个指向数组的指针
7.7.1形式参数是一个指针
c++
void myFunc(int *param)
{
...
...
...
}
7.7.2形式参数是一个已定义大小的数组
c++
void myFunc(int param[10])
{
...
...
...
}
7.7.3形式参数是一个未定义大小的数组
c++
void myFunc(int param[])
{
...
...
...
}
7.8从函数返回数组
-
不允许返回一个完整的数组作为函数的参数,可以通过指定不带索引的数组名来返回一个指向数组的指针
c++int * myFunc(){ //... }
c++int * myFunc(){ int myArray[3] = {1,2,3}; return myArray; }
c++#include <iostream> using namespace std; int* createArray(int size) { int* arr = new int[size]; for (int i = 0; i < size; i++) { arr[i] = i + 1; } return arr; } int main() { int* myArray = createArray(5); for (int i = 0; i < 5; i++) { cout << myArray[i] << " "; } cout << endl; delete[] myArray; // 释放内存 return 0; }
8.C++字符串
- C++提供了两种类型的字符串表示形式
- C风格字符串
- C++引入的string类类型
8.1C风格字符串
-
字符串实际上是使用null字符
\0
终止的一维字符数组,因此以null结尾的字符串,包含了组成字符串的字符c++// // Created by 16690 on 2024/4/19. // #include <iostream> #include <cstring> using namespace std; int main(void) { char site1[11] = {'H', 'E', 'L', 'L', 'O', 'W', 'O', 'R', 'L', 'D', '\0'}; char site2[] = "HELLOWORLD"; for (int i = 0; i < strlen(site1); i++) { cout << site1[i] << endl; } cout << "-------------------------" << endl; for (int i = 0; i < sizeof(site2) / sizeof(site2[0]); i++) { cout << site2[i] << endl; } return 0; }
序号 | 函数 & 目的 |
---|---|
1 | strcpy(s1, s2); 复制字符串 s2 到字符串 s1。 |
2 | strcat(s1, s2); 连接字符串 s2 到字符串 s1 的末尾。连接字符串也可以用 + 号,例如: string str1 = "runoob"; string str2 = "google"; string str = str1 + str2; |
3 | strlen(s1); / length(); / size(); 返回字符串 s1 的长度。 |
4 | strcmp(s1, s2); 如果 s1 和 s2 是相同的,则返回 0;如果 s1<s2 则返回值小于 0;如果 s1>s2 则返回值大于 0。**s1.compare(s2);**若相同返回0,否则返回-1 |
5 | strchr(s1, ch); 返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。 |
6 | strstr(s1, s2); 返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。 |
7 | **append(s1);**在字符串的末尾添加字符 |
8 | **find(s1);**在字符串中查找字符串 |
9 | **insert(插入位置,str);**插入字符 |
10 | **replace(str, num,"");**替换字符串,在str中,之后的第num个字符替换为空,即删除 |
11 | **substr(start, end);**返回某个子字符串,包括起始位置和结束位置 |
8.2C++中的string类
c++
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string str1 = "runoob";
string str2 = "google";
string str3;
int len ;
// 复制 str1 到 str3
str3 = str1;
cout << "str3 : " << str3 << endl;
// 连接 str1 和 str2
str3 = str1 + str2;
cout << "str1 + str2 : " << str3 << endl;
// 连接后,str3 的总长度
len = str3.size();
cout << "str3.size() : " << len << endl;
return 0;
}
8.3输入字符串
8.3.1cin >>
-
接收用户的输入包括数字、字符串(遇到空格、tab、回车结束)
c++cout << "请输入一个整数:"; int num; cin >> num; cout << "你输入的整数是:" << num << endl;
8.3.2cin.get >>
-
cin.get(字符变量名)可以用来接收字符
c++char ch; cout << "请输入一个字符:"; cin.get(ch); cout << "ch="<<ch <<endl;
-
cin.get(字符数组名,接收字符数)用来接收一行字符串,可以接收空格
c++char ch[10]; cout << "请输入字符串:"; cin.get(ch,10); cout << "ch="<<ch <<endl;
-
cin.get(无参数)没有参数主要是用于舍弃输入流中的不需要的字符, 或者舍弃回车, 弥补cin.get(字符数组名,接收字符数目)的不足.
c++char ch[10]; cin.get(ch, 10); //用于吃掉回车,相当于getchar(); cin.get(); cout << "ch=" << ch << endl;
8.3.3cin.getline();
-
cin.getline(str, 接收的字符个数): 接受一个字符串,可以接收空格并输出
c++char ch[20]; //接收5个字符的字符串,但是最后一个是'\0' cin.getline(ch, 5); //与上面基本相同。 cout << "ch=" << ch << endl;
-
cin.getline(str, 接收的字符个数, 结束的字符): 接受一个字符串,可以接收空格并输出
c++char ch[20]; //接收5个字符的字符串 cin.getline(ch, 5,'c'); //与上面基本相同。 cout << "ch=" << ch << endl;
8.3.4getline();
-
getline() :接受一个字符串,可以接收空格并输出,需包含 #include
c++string str; getline(cin,str); cout << "str=" << str << endl;
8.3.5gets();
-
gets(): 接受一个字符串,可以接收空格并输出,需包含 #include
c++char ch[20]; gets(ch); cout << "ch=" << ch << endl;
8.3.6getchar();
-
getchar() :接受一个字符,需包含 #include
c++char ch; ch = getchar(); cout << "ch=" << ch << endl;
8.3.7原始打印R"(str)"
c++
cout << R"(sdfj\8sl**!#$%^&\n\t*(\))" << ch << endl;
9.C++指针
- 指针是一个变量,其值为另一个变量的地址,即内存位置的直接地址
- 语法:
数据类型 *变量名;
-
& 是取地址,也就是返回一个对象在内存中的地址。
-
***** 是取得一个指针所指向的对象,也就是当一个指针保存着一个内存地址,那么它就返回在那个地址的对象。
9.1C++中使用指针
-
定义一个指针变量、把变量地址赋值给指针、访问指针变量中可用地址的值
c++#include <iostream> using namespace std; int main () { int var = 20; // 实际变量的声明 int *ip; // 指针变量的声明 ip = &var; // 在指针变量中存储 var 的地址 cout << "Value of var variable: "; cout << var << endl; // 输出在指针变量中存储的地址 cout << "Address stored in ip variable: "; cout << ip << endl; // 访问指针中地址的值 cout << "Value of *ip variable: "; cout << *ip << endl; return 0; }
9.2NULL空指针
-
NULL 指针是一个定义在标准库中的值为零的常量
c++// // Created by 16690 on 2024/4/19. // #include <iostream> using namespace std; int main(void){ int *ptr = NULL; cout << "ptr的值=" << ptr; return 0; }
-
可用使用if语句来使用这一特性
c++if(ptr) /* 如果 ptr 非空,则完成 */ if(!ptr) /* 如果 ptr 为空,则完成 */
9.3指针的算术运算
-
指针是一个用数值表示的地址 ,因此可以对指针执行算术运算。可以对指针进行四种算术运算:++、--、+、-
-
指针的算术运算
- 加法运算 :可以对指针进行加法运算,当一个指针p加上一个整数n时,结果是指针p向前移动n个元素的大小。例如,若是int类型的指针,每个int占4个字节,那么p+1将指向p所指向的下一个int元素
- 减法运算 :可以对指针进行减法运算,当一个指针p减去一个整数n时,结果是指针p向后移动n个元素的大小。例如,若是int类型的指针,每个int占4个字节,那么p-1将指向p所指向的前一个int元素
- 指针之间的减法运算 :可以计算两个指针的距离,当从一个指针p减去另一个指针q时,结果是两个指针之间的元素个数。例如,若是p和q是两个int类型的指针,每个int占4个字节,那么p-q将得到两个指针之间的元素个数
- 指针与整数之间的比较运算 ,可以将指针与整数进行比较运算,可以使用关系运算符(如<、>、<=、>=)对指针和整数进行比较,通常用于判断指针是否指向某个有效的内存位置
9.3.1递增/递减指针
-
使用指针代替数组,因为变量指针可以递增,而数组不能递增,因为数组是一个常量指针
c++// // Created by 16690 on 2024/4/19. // #include <iostream> using namespace std; const int MAX = 3; int main(void) { int var[MAX] = {10, 33, 77}; int *ptr; //指向数组 //递增指针 ptr = var; for (int i = 0; i < MAX; i++) { cout << "address[" << i << "]=" << ptr << endl; cout << "value[" << i << "]=" << *ptr << endl; ptr++; } cout <<"----------------------------------"<< endl; //递减指针 ptr = &var[MAX-1]; cout << "address[MAX]=" << &var[MAX-1] << endl; for(int i=MAX;i>0;i--){ cout << "address[" << i << "]=" << ptr << endl; cout << "value[" << i << "]=" << *ptr << endl; ptr--; } return 0; }
9.3.2指针的比较
-
指针可以用关系运算符进行比较,如 ==、< 和 >,前提是 p1 和 p2 指向同一个数组中的不同元素
c++// // Created by 16690 on 2024/4/19. // #include <iostream> using namespace std; const int MAX = 3; int main(void) { int var[MAX] = {10, 33, 77}; int *ptr; ptr=var; int i=0; while(ptr <= &var[MAX-1]){ cout << "address[" << i << "]=" << ptr << endl; cout << "value[" << i << "]=" << *ptr << endl; ptr++; i++; } return 0; }
9.4指针和数组
-
指针和数组在很多情况下是可以互换的
c++// // Created by 16690 on 2024/4/19. // #include <iostream> using namespace std; #define MAX 5 int main(void){ int var[MAX] = {10, 20, 30, 40, 50}; // 赋值方式1 // int *ptr = var; // 赋值方式2 int *ptr = &var[0]; for(int i=0;i<MAX;i++){ //遍历方式1,先指向值,再自增到下一个值 // cout<<"*ptr++" << *ptr++ <<endl; //遍历方式2,先自增,然后再取当前的值,因为++的原因,所以需要到下一次才取到下一次的值 // cout<<"*(ptr++)" << *(ptr++) <<endl; //遍历方式3,因为i从0开始自增,所以直接获取当前的值 // cout<<"*var+i" << *(var+i) <<endl; //遍历方式4,因为i从0开始自增,所以直接获取当前的值 // cout<<"*var+i" << var[i] <<endl; //遍历方式5,因为i从0开始自增,所以直接获取当前的值 cout<<"*var+i" << ptr[i] <<endl; } return 0; }
9.5指针数组
-
让数组存储指向int或char或其他数据类型数组的指针
c++// // Created by 16690 on 2024/4/19. // #include <iostream> using namespace std; #define MAX 5 int main(void){ int var[MAX] = {10, 20, 30, 40, 50}; int *ptrs[MAX]; for(int i=0;i<MAX;i++){ ptrs[i] = &var[i]; } for(int i=0;i<MAX;i++){ cout<<"*ptrs[i]=" << *ptrs[i] <<endl; } return 0; }
int *ptr[3]; int *(ptr[3]);
ptr 先和 [] 结合成为数组,然后再和 int * 结合形成数组的元素类型是 int * 类型,得到指向一维数组的指针数组。
int (*ptr)[3];
先是 () 里的 ***** 和 ptr 结合成为一个指针,然后是 (*ptr) 和 [] 相结合成为一个数组,最后指针 ptr 指向一维数组,简称数组指针。
9.6指向指针的指针
-
指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链
-
指针的指针就是将指针的地址存放在另一个指针里面
c++// // Created by 16690 on 2024/4/19. // #include <iostream> using namespace std; int main(void){ int var = 10; int *ptr= &var; int **ptrs = &ptr; cout << "var = " << var << endl; cout << "*ptr = " << *ptr << endl; cout << "**ptrs = " << **ptrs << endl; cout << "&var = " << &var << endl; cout << "ptr = " << ptr << endl; cout << "ptrs = " << ptrs << endl; return 0; }
9.7传递指针给函数
-
传递指针给函数,只需要简单地声明函数参数为指针类型
c++// // Created by 16690 on 2024/4/19. // #include <iostream> using namespace std; void getSeconds(unsigned long *ptr); int main(void){ unsigned long sec; getSeconds(&sec); //输出实际值 cout << "Number of seconds:" <<sec <<endl; return 0; } void getSeconds(unsigned long *ptr){ //获取当前的秒数 *ptr = time(NULL); return; }
9.8从函数返回指针
-
语法:
c++int * myFunc(){ ... ... ... }
c++// // Created by 16690 on 2024/4/19. // #include <iostream> using namespace std; int * getRandom(); int main(void) { int *p=getRandom(); for (int i = 0; i < 10; ++i) { cout << "*p[" << i << "]=" << *p << endl; *(p++); } return 0; } int * getRandom() { //存放所有的随机数 static int r[10]; //存放随机数 int result = 0; //设置种子 srand((unsigned) time(NULL)); for (int i = 0; i < 10; ++i) { result = rand() % (1 - 1 + 100) +1; r[i] = result; cout << "r[i]=" << r[i] << endl; } return r; }
10.C++引用
- 引用变量是一个别名,是已存在变量的另一个名字
- 将引用初始化某个变量,就可以使用该引用名称或变量名称来指向变量
10.1引用和指针
- 不存在空引用,引用必须连接到一块合法的内存
- 一旦引用 被初始化为一个对象,就不能被指向到另一个对象;指针可以在任何时候指向到另一个对象
- 引用 必须在创建时被初始化;指针可以在任何时间被初始化
10.2C++创建引用
-
变量名称是变量附属在内存位置中的标签,可以将引用当成是变量附属在内存中的第二个标签
-
可以通过原始变量名称或引用名称来访问变量的内容
c++// // Created by 16690 on 2024/4/19. // #include <iostream> using namespace std; int main(void) { //声明简单的变量 int i; double d; //声明引用的变量 int &r = i; double &s = d; i=5; cout << "value=" << i << endl; cout << "reference value=" << r << endl; d=10.5; cout << "value=" << d << endl; cout << "reference value=" << s << endl; return 0; }
10.3将引用作为参数
c++
//
// Created by 16690 on 2024/4/19.
//
#include <iostream>
void swap(int &a, int &b);
using namespace std;
int main(void) {
//传递实参
int a = 100;
int b = 200;
//传递指针
int *ptra = &a;
int *ptrb = &b;
//传递引用
int &ra = a;
int &rb = b;
cout << "交换前,a的值" << a << endl;
cout << "交换前,b的值" << b << endl;
// swap(a, b);
// swap(*ptra, *ptrb);
swap(ra,rb);
cout << "交换后,a的值" << a << endl;
cout << "交换后,b的值" << b << endl;
return 0;
}
void swap(int &x, int &y) {
int temp;
temp = x;
x = y;
y = temp;
return;
}
10.4将引用作为返回值
- 不能返回局部变量的引用,因为局部变量在函数返回后会销毁
- 不能返回函数内部new分配的内存引用
- 可以返回类成员的引用,最好是const
c++
//
// Created by 16690 on 2024/4/19.
//
#include <iostream>
using namespace std;
double vals[] = {1000.0, 2.5, 1000.0};
double &setValues(int i) {
//创建引用
double &ref = vals[i];
cout << "ref=" << ref << endl;
return ref;
}
int main(void) {
cout << "改变前的值" << endl;
for (int i = 0; i < 3; i++) {
cout << "vals[" << i << "]=" << vals[i] << endl;
}
setValues(1) = 20.23;
cout << "setValues(1)=" << setValues(1) << endl;
setValues(2) = 888.888;
cout << "改变后的值" << endl;
for (int i = 0; i < 3; i++) {
cout << "vals[" << i << "]=" << vals[i] << endl;
}
return 0;
}