# 数组、字符串和指针

24 篇文章 3 订阅

## 数组

### 声明数组

type arrayName[size];

### 初始化数组

type arrayName[size]{ value 1,value 2,...,value n};

type arrayName[] = { value 1,value 2,...,value n};

### 基于范围的for循环

for(type item:array)        //可以使用auto关键字
{
//user code
}

C++库提供了——countof()函数，可以获取数组中的元素个数。

	int a[]{1,2,3,4,5};
std::cout << _countof(a) << std::endl;
for (int item:a)
{
std::cout << item << std::endl;
}

#### 范例：

#include <iostream>
using namespace std;

int main()
{
//4.1 数组
cout << "数组" << endl;
int data1[3]{1, 2, 3};//初始化1
int data2[3]{ };//初始化2，填充0
int data3[]{ 1, 2, 3 };//初始化3
for (int i : data1)
{
cout << i << endl;
}
cout << "sizeof(data1[0]):" << sizeof(data1[0]) << endl;//int 4字节
cout << "sizeof(data1):" << sizeof(data1)<<endl;//12字节
cout << "_countof(data1):" << _countof(data1) << endl;//3
cout <<endl;
}

output:

1
2
3
sizeof(data1[0]):4
sizeof(data1):12
_countof(data1):3


## 多维数组

### 声明

type arrayName[size1][size2];

### 初始化

type arrayName[size1][size2]= {
{ value 1,value 2,...,value n},
{ value 1,value 2,...,value n}
};
int data1[2][4]  {  { 1,2,3,4},{ 5,6,7,8}  };

//可以省略某些初始值
int data2[2][4]  {  { 1,2,3}, { 5,6}  };

//用0初始化数组
int data2[2][4]  { };

#### 范例：

#include <iostream>
using namespace std;

int main()
{
cout << "多维数组" << endl;
int data4[2][4]{ {1,2,3,4},{5,6,7,8} };//初始化1
int data5[2][4]{ };//初始化2，填充0
int data6[][4]{ {1,2,3,4},{5,6,7,8} };//初始化3
cout << "sizeof(data6[0][0]):" << sizeof(data6[0][0]) << endl;//int 4字节
cout << "sizeof(data6[0]):" << sizeof(data6[0]) << endl;//16字节
cout << "sizeof(data6):" << sizeof(data6) << endl;//32字节
cout << "_countof(data6[0]):" << _countof(data6[0]) << endl;//4
cout << "_countof(data6):" << _countof(data6) << endl;//2
cout << "---------------------------------------------" << endl << endl;
}

output:

sizeof(data6[0][0]):4
sizeof(data6[0]):16
sizeof(data6):32
_countof(data6[0]):4
_countof(data6):2


## 字符串

#include "pch.h"
#include <iostream>

int main()
{
char a[] {"123456789"};
std::cout << a << std::endl << sizeof(a) << std::endl;

wchar_t b[]{ L"ABC" };
std::wcout << b << std::endl << sizeof(b) << std::endl;

}

wcout标准输出流（宽）。

### 输入

cin.get()和cin.geline()，从键盘输入的字符串序列，并将其以字符串的形式（以‘\0‘字符串终止）存入字符数组中。

#include "pch.h"
#include <iostream>

int main()
{
char a[20] {};
std::cin.get(a,20);
std::cout << a << std::endl << sizeof(a) << std::endl;
}

getline成员函数类似于函数get。 这两个函数均允许用于指定输入终止字符的第三个参数。

#include "pch.h"
#include <iostream>

int main()
{
char a[20] {};
std::cin.getline(a,20,'5');
std::cout << a << std::endl << sizeof(a) << std::endl;
}

### 字符串的字面量

R表示原字符串字面量的开头，字符串用"(和)"界定。

#include "pch.h"
#include <iostream>

int main()
{
char a[] { "123\0\n" };
std::cout << a << std::endl << sizeof(a) << std::endl;

char b[]{ R"(123\0\n)" };
std::cout << b << std::endl << sizeof(b) << std::endl;

char c[]{ R"*+(123\0\n)*+" };
std::cout << c << std::endl << sizeof(c) << std::endl;
}

123
6
123\0\n
8
123\0\n
8

### 字符串的for循环

#include "pch.h"
#include <iostream>

int main()
{
char a[] { "123" };
for (auto item:a)
{
std::cout << item  << std::endl;
}

}

1
2
3

#### 范例：

#include <iostream>
using namespace std;

int main()
{
cout << "字符串" << endl;
char sentences[2][20]{ {"(It is \n a pig)"},{R"(It is \n a pig)"} };
for (auto a : sentences)
{
cout << a << endl;
}
cout << "---------------------------------------------" << endl << endl;
}

output:

(It is
a pig)
It is \n a pig
---------------------------------------------


## 间接数据访问

### 指针

#### 声明指针

int* pb;
int *pc;

#### 取值运算符

&，一元运算符，用于获取变量的地址，也称为引用运算符。

#### 使用指针

#include "pch.h"
#include <iostream>

int main()
{
int b {123456};
int* pb;
pb = &b;
std::cout << "b: " << b << std::endl;
std::cout << "&b: " << &b << std::endl;
std::cout << "pb: " << pb << std::endl;
std::cout << "&pb: " << &pb << std::endl;
std::cout << "*pb: " << *pb << std::endl;
}

b: 123456
&b: 000000DBCF9BFB84
pb: 000000DBCF9BFB84
&pb: 000000DBCF9BFBA8
*pb: 123456

#### 初始化指针

	int b {123456};
int* pb{& b};
int* pb{ nullptr };
int* pb{ 0 };		//旧方法
int* pb{ NULL };	//旧方法

nullptr可以隐式转换成任何指针类型，但不能隐式转换为除bool类型以外的其他任何整数类型。


int* pb {nullptr};
if(!pb)
//user code

#### 指向char类型的指针

const char* 类型的指针可以用字符串字面值初始化。

const char* pb{"123"};

### 指针数组

##### sizeof操作符

sizeof操作符产生size_t类型的整数值，给出其操作数占用的字节数量，size_t是由标准库定义的类型。

_countof()可以得到数组元素的个数。

#include "pch.h"
#include <iostream>

int main()
{
int b[] {123,456,789};
std::cout << "sizeof b: " << sizeof b << std::endl;
std::cout << "_countof b: " << _countof(b) << std::endl;
}

sizeof b: 12
_countof b: 3

##### 常量指针和指向常量的指针

const的指针中存储const数组的地址，这将阻止修改用作初始化器的字面值，此时const指针的地址可以修改。

#include "pch.h"
#include <iostream>

int main()
{
const int a { 1 };
const int b { 2 };
const int* ptr{ &a };
ptr = { &b };
}

const type* const指针将阻止修改字面值和指针地址。

#include "pch.h"
#include <iostream>

int main()
{
const int a { 1 };
const int b { 2 };
const int* const ptr{ &a };
ptr = { &b };	//报错
}
 指针 对象（的值） 指针指向 指向常量对象的指针 不能修改 可以修改 指向某个对象的常量指针 可以修改 不能修改 指向常量对象的常量指针 不能修改 不能修改

#### 指针和数组

#include "pch.h"
#include <iostream>

int main()
{
int a[5];
int* b { nullptr};
b = a;
std::cout << b << std::endl;
b = &a[0];
std::cout << b << std::endl;
}

#include "pch.h"
#include <iostream>

int main()
{
int data[5]{ 2,4,6,8,10 };
int* pdata{ nullptr };
pdata = &data[2];
std::cout << *(pdata + 1) << std::endl;
pdata = &data[2];
std::cout << *(pdata - 1) << std::endl;
}

#### 指针与多维数组

#include "pch.h"
#include <iostream>

int main()
{
int data[2][3]{ {2,4,6},{1,2,3} };
int* pdata{ nullptr };
pdata = data[0]; //将1维数组的地址赋予指针
std::cout << *pdata << std::endl;
pdata = &data[0][0];
std::cout << *pdata << std::endl;
int (*pdata2)[3];//指针类型是int*[3],圆括号是必须得，否则声明的是一个指针数组。该指针只能用来存储规定维度的数组的地址。
pdata2 = data;
std::cout << *pdata2 << std::endl;
}
##### 多维数组的指针形式

• 使用带2个索引值得数组名。
• 使用指针形式的数组名。
#include "pch.h"
#include <iostream>

int main()
{
int data[2][3]{ {2,4,6},{1,2,3} };
int* pdata{ nullptr };
pdata = data[0]; //将1维数组的地址赋予指针
std::cout << data[1][1] << std::endl;
std::cout << *(*(data+1)+1) << std::endl;
std::cout << *(data[1] + 1) << std::endl;
}

#### 范例：

#include <iostream>
using namespace std;

int main()
{
//4.3 间接访问
cout << "间接访问" << endl;
int num{ 8888 };
int* pnum1{ &num };//初始化
cout << "num: " << num << endl;//8888
cout << "&num: " << &num << endl;//地址
cout << "pnum1: " << pnum1 << endl;//地址
cout << "*pnum1: " << *pnum1 << endl;//8888
cout << "pnum1 + 1: " << pnum1 + 1 << endl;//地址 + 1单位类型
cout << "*(pnum1 + 1): " << *(pnum1 + 1) << "（超出界限的指针）" << endl;
pnum1 = nullptr;
cout << "pnum1 = nullptr: " << pnum1 << endl; //0
cout << endl;

const char* pstr1{ "AbCdEfG" };
cout << "pstr1: " << pstr1 << endl;//AbCdEfG
cout << "*pstr1: " << *pstr1 << endl;//A
cout << "*(pstr1 + 1): " << *(pstr1 + 1) << endl;//b
cout << "*pstr1 + 1: " << *pstr1 + 1 << endl;//66,也就是B
cout << "(sizeof pstr1) / (sizeof pstr1[0]): " << (sizeof pstr1) / (sizeof pstr1[0]) << R"( （包含末尾的'\0'）)" << endl;//8,包含末尾的 '\0'
int count{ 0 };
while (*pstr1++)
{
count++;
}
cout << "count: " << count << R"( （不包含末尾的'\0'）)" << endl;//7
cout << endl;

const char* pstr2[3];
pstr2[0] = { "AbCdEfG" };
pstr2[1] = { "HiJkLmN" };
pstr2[2] = { "OpQrSt" };

//数组首地址和数组元素地址
cout << "&pstr2: " << &pstr2 << endl;  //数组首地址
cout << "pstr2: " << pstr2 << endl;//数组首地址
cout << "&pstr2[1]: " << &pstr2[1] << endl;//数组元素1的地址

//数组元素
cout << "pstr2[0]: " << pstr2[0] << endl;//AbCdEfG
cout << "*pstr2: " << *pstr2 << endl;//AbCdEfG
cout << "pstr2[1]: " << pstr2[1] << endl;//HiJkLmN
cout << "*(pstr2 + 1): " << *(pstr2 + 1) << endl;//HiJkLmN

//二位数组元素中的元素
cout << "pstr2[1][0]: " << pstr2[1][0] << endl;//H
cout << "*pstr2[1]: " << *pstr2[1] << endl;//H
cout << "pstr2[1][1]: " << pstr2[1][1] << endl;//i
cout << "*(pstr2[1] + 1): " << *(pstr2[1] + 1) << endl;//i
cout << "(*pstr2[1] + 1): " << (*pstr2[1] + 1) << endl;//bCdEfG
cout << "(*pstr2 + 1)[1]: " << (*pstr2 + 1)[1] << endl;//C

cout << "*pstr2 + 1: " << *pstr2 + 1 << endl;//bCdEfG
cout << "*pstr2[0] + 1: " << *pstr2[0] + 1 << endl;//66,也就是B
cout << endl;

int arr_int1[]{ 1,3,5,7,9 };
int* parr_int{ &arr_int1[1] };
cout << "*arr_int1: " << *parr_int << endl;//3
cout << "*++arr_int1: " << *++parr_int << endl;//5
cout << endl;

//多维数组的指针
//Array[i][j]
//*(*(Array + i) +j)
int  arr_int2[2][3]{ {1,2,3},{7,8,9} };
int* parr_int2_1{ &arr_int2[1][1] };
int* parr_int2_2{ arr_int2[1] };
auto parr_int2_3{ arr_int2 };
int(*parr_int2_4)[3]{ arr_int2 };
cout << "arr_int2[2][3]:{ {1,2,3},{7,8,9} }" << endl;
cout << "int* parr_int2_1{ &arr_int2 [1][1]}: " << *parr_int2_1 << endl;//8
cout << "*(*(arr_int2 + 1) +1): " << *(*(arr_int2 + 1) + 1) << endl;//8
cout << "int* parr_int2_2{ arr_int2[1]}: " << *parr_int2_2  << endl;//7
cout << "*arr_int2: " << arr_int2 << endl;//地址
cout << "auto parr_int2_3{ arr_int2 }: " << *parr_int2_3 << endl;//地址
cout << "(*parr_int2_4)[3]{ arr_int2 }: " << *parr_int2_4 << endl;//地址
cout << "---------------------------------------------" << endl << endl;
}

output:

num: 8888
&num: 006FFBF0
pnum1: 006FFBF0
*pnum1: 8888
pnum1 + 1: 006FFBF4
*(pnum1 + 1): -858993460（超出界限的指针）
pnum1 = nullptr: 00000000

pstr1: AbCdEfG
*pstr1: A
*(pstr1 + 1): b
*pstr1 + 1: 66
(sizeof pstr1) / (sizeof pstr1[0]): 4 （包含末尾的'\0'）
count: 7 （不包含末尾的'\0'）

&pstr2: 006FFBB8
pstr2: 006FFBB8
&pstr2[1]: 006FFBBC
pstr2[0]: AbCdEfG
*pstr2: AbCdEfG
pstr2[1]: HiJkLmN
*(pstr2 + 1): HiJkLmN
pstr2[1][0]: H
*pstr2[1]: H
pstr2[1][1]: i
*(pstr2[1] + 1): i
(*pstr2[1] + 1): 73
(*pstr2 + 1)[1]: C
*pstr2 + 1: bCdEfG
*pstr2[0] + 1: 66

*arr_int1: 3
*++arr_int1: 5

arr_int2[2][3]:{ {1,2,3},{7,8,9} }
int* parr_int2_1{ &arr_int2 [1][1]}: 8
*(*(arr_int2 + 1) +1): 8
int* parr_int2_2{ arr_int2[1]}: 7
*arr_int2: 006FFB70
auto parr_int2_3{ arr_int2 }: 006FFB70
(*parr_int2_4)[3]{ arr_int2 }: 006FFB70
---------------------------------------------

## 动态分配内存

new操作符：动态分配内存。

delete操作符：释放new分配的内存。

#include "pch.h"
#include <iostream>

int main()
{

int* pdata = new int{ 123 };
std::cout << *pdata << std::endl;
delete pdata;
std::cout << *pdata << std::endl;	//引发异常
}

### 为数组动态分配内存

#include "pch.h"
#include <iostream>

int main()
{

int* pdata{ new int[]{1,2,3,4,5,6,7,8,9} };
std::cout << *pdata << std::endl;
delete [] pdata;
//std::cout << *pdata << std::endl;	//引发异常
pdata = nullptr;

}

delete后的方括号指出要删除的是一个数组。还应该将指针设置为nullptr。

### 多维数组的动态分配内存

#include "pch.h"
#include <iostream>

int main()
{

int(*pdata)[3]{ new int[][3]{{1,2,3},{4,5,6}} };
auto pdata2 { new int[][3]{{1,2,3},{4,5,6}} };
std::cout << **pdata << std::endl;
std::cout << **pdata2 << std::endl;
delete [] pdata;
//std::cout << *pdata << std::endl;	//引发异常
pdata = nullptr;
}

#### 范例：

#include <iostream>
#include <iomanip>
using namespace std;

int main()
{
//4.4 动态分配内存
//int* parr{};
//parr = new int{ 888 };
cout << "动态分配" << endl;
int* parr{ new int{ 888 } };
cout << "*parr: " << *parr << endl;
delete parr;
parr = nullptr;

int* parr2{ new int[] {333, 444} };
cout << "*parr2: " << *parr2 << endl;//333
cout << "*(parr2 + 1): " << *(parr2 + 1) << endl;//444
unsigned long long address = (unsigned long long)parr2;
cout << "parr2: " << parr2 << endl;
cout << "address: " << hex << setfill('0') << setw(16) << uppercase << address << endl;

int result1 = *(int*)address;
cout << "result1: " << dec << result1 << endl;
delete[] parr2;
parr2 = nullptr;
int result2 = *(int*)address;
cout << "After delete[] parr2, result2: " << dec << result2 << endl;
cout << "---------------------------------------------" << endl << endl;
}

output:

*parr: 888
*parr2: 333
*(parr2 + 1): 444
parr2: 011BF370
result1: 333
After delete[] parr2, result2: -572662307
---------------------------------------------



## 使用引用

lvalue是另一个变量的别名。

rvalve引用也可以用作变量的别名，但它与lvalue引用的区别在于，它也能引用rvalve，这实质上是一个暂存的临时值。

### 声明初始化lvalue

#include "pch.h"
#include <iostream>

int main()
{
int a{ 1 };
int& lvalue{ a };	//声明变量的引用
const int& lvalue2 {2};	//声明变量的引用
std::cout << lvalue << std::endl;
std::cout << lvalue2 << std::endl;
}

### 基于范围的for循环中使用引用

#include "pch.h"
#include <iostream>

int main()
{
int a[]{ 1,2,3 };
for(int item:a)
std::cout << item << std::endl;

for (int& item : a)
{
item = item + 3;
std::cout << item << std::endl;
}

for (const int& item : a)	//不修改，提高性能用const
{
std::cout << item << std::endl;
}
}

### 创建rvalve引用

C++表达式，要么是lvalve，要么是rvalve

#include "pch.h"
#include <iostream>

int main()
{
int && a{2*3 };	//rvalve，仅演示用，不是使用rvalve的方式
std::cout << a;
}

#### 范例：

#include <iostream>
#include <iomanip>
using namespace std;

int main()
{
//4.5 引用
cout << "引用" << endl;
int alvalue{ 99 };//lvalue
int& re_alvalue1{ alvalue };//可以用引用代替原来的变量名
const int& re_alvalue2{ 88 };//
int* p_re_alvalue1{ &re_alvalue1 };

cout << "alvalue: " << alvalue << endl;
cout << "re_alvalue1: " << re_alvalue1 << endl;
cout << "*p_re_alvalue1: " << *p_re_alvalue1 << endl;
*p_re_alvalue1 += 1;
cout << "*p_re_alvalue1 += 1" << endl;
cout << "alvalue: " << alvalue << endl;
cout << "re_alvalue1: " << re_alvalue1 << endl;
cout << "*p_re_alvalue1: " << *p_re_alvalue1 << endl;

cout << endl;
//在基于范围的for循环中
int aArr[]{ 333, 444 };
cout << "int t:" << endl;
for (int t : aArr)
{
t++;
}
for (int t : aArr)
{
cout << "aArr: " << t << endl;
}
cout << endl;
cout << "int& t:" << endl;
for (int& t : aArr)
{
t++;
}
for (int& t : aArr)
{
cout << "aArr: " << t << endl;
}
cout << endl;
int&& re_rvalue3{ alvalue + 1 };//rvalue的引用
cout << "re_rvalue3: " << re_rvalue3 << endl;
}

output:

alvalue: 99
re_alvalue1: 99
*p_re_alvalue1: 99
*p_re_alvalue1 += 1
alvalue: 100
re_alvalue1: 100
*p_re_alvalue1: 100

int t:
aArr: 333
aArr: 444

int& t:
aArr: 334
aArr: 445

re_rvalue3: 101



## 字符串库函数

string标准头文件定义了string和wstring类。

#include "pch.h"
#include <atlstr.h>

int main() {
CString aCString = CString(_T("A string"));
_tprintf(_T("%s"), (LPCTSTR)aCString);
}

### 通过使用当前区域设置或指定区域设置获取字符串的长度

strnlen、strnlen_s、wcsnlen、wcsnlen_s、_mbsnlen、_mbsnlen_l、_mbstrnlen、_mbstrnlen_l | Microsoft Docshttps://docs.microsoft.com/zh-cn/cpp/c-runtime-library/reference/strnlen-strnlen-s?view=msvc-170

### 追加字符串

strcat_s、wcscat_s、_mbscat_s、_mbscat_s_l | Microsoft Docs详细了解：strcat_s、wcscat_s、_mbscat_s、_mbscat_s_lhttps://docs.microsoft.com/zh-cn/cpp/c-runtime-library/reference/strcat-s-wcscat-s-mbscat-s?view=msvc-170

### 复制字符串

strcpy_s、wcscpy_s、_mbscpy_s、_mbscpy_s_l | Microsoft Docs了解详细信息： strcpy_s、wcscpy_s、_mbscpy_s、_mbscpy_s_lhttps://docs.microsoft.com/zh-cn/cpp/c-runtime-library/reference/strcpy-s-wcscpy-s-mbscpy-s?view=msvc-170

### 比较字符串

strcmp、wcscmp、_mbscmp、_mbscmp_l | Microsoft Docs了解：strcmp、wcscmp、_mbscmp、_mbscmp_lhttps://docs.microsoft.com/zh-cn/cpp/c-runtime-library/reference/strcmp-wcscmp-mbscmp?view=msvc-170

### 返回不属于某个字符集的字符串中第一个字符的索引

strspn、wcsspn、_mbsspn、_mbsspn_l | Microsoft Docs了解详细信息： strspn、wcsspn、_mbsspn、_mbsspn_lhttps://docs.microsoft.com/zh-cn/cpp/c-runtime-library/reference/strspn-wcsspn-mbsspn-mbsspn-l?view=msvc-170

• 0
点赞
• 2
收藏
觉得还不错? 一键收藏
• 0
评论
07-04
07-06 2518
03-21 619
06-11 2601
04-27 9577
07-11
12-19 271
07-23 1868
02-15 1477
05-28 2130

### “相关推荐”对你有帮助么？

• 非常没帮助
• 没帮助
• 一般
• 有帮助
• 非常有帮助

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、付费专栏及课程。