C++入门教程:数组、字符串与指针入门
🕒 阅读时间:16 分钟📝 字数:2340👀 阅读量:Loading...
本文摘要
本文是C++系列教程的第4篇,重点讲解数组、字符串和指针的核心概念。主要内容包括:1) 一维/多维数组的声明、初始化和遍历,强调数组越界的危险性;2)…
本文是 C++ 系列教程的第 4 篇。上一篇讲解了函数与作用域,本篇深入讲解数组、字符串和指针:一维/多维数组、C 风格字符串与 std::string、指针基础、指针与数组的关系、引用与 const 限定。
一、数组
1.1 一维数组
数组是同类型元素的集合,内存中连续存储:
#include <iostream>using namespace std;
int main() { // 声明与初始化 int scores[5]; // 未初始化(含垃圾值) int nums[5] = {1, 2, 3, 4, 5}; // 列表初始化 int partial[5] = {1, 2}; // 其余补 0 int autoSize[] = {10, 20, 30}; // 自动推导大小为 3
// 访问与修改 cout << "nums[0] = " << nums[0] << endl; // 1 nums[2] = 100; // 修改第三个元素 cout << "修改后 nums[2] = " << nums[2] << endl; // 100
// 遍历 for (int i = 0; i < 5; i++) { cout << nums[i] << " "; } cout << endl; return 0;}1.2 数组越界(危险!)
#include <iostream>using namespace std;
int main() { int arr[3] = {1, 2, 3}; // arr[3] 越界访问:编译不报错,但行为未定义 // 可能读到垃圾值,甚至修改其他内存导致崩溃 cout << "越界访问 arr[3] = " << arr[3] << "(未定义行为!)" << endl; return 0;}数组下标从 0 开始,合法范围是 0 ~ 大小-1。C++ 不检查越界,这是很多 bug 的根源。
1.3 多维数组
#include <iostream>using namespace std;
int main() { // 3x4 二维数组(3 行 4 列) int matrix[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };
// 遍历 for (int i = 0; i < 3; i++) { for (int j = 0; j < 4; j++) { cout << matrix[i][j] << "\t"; } cout << endl; } return 0;}1.4 数组与范围 for
C++11 起可用范围 for 遍历数组:
#include <iostream>using namespace std;
int main() { int nums[] = {5, 10, 15, 20};
// 范围 for:只读 for (int n : nums) { cout << n << " "; } cout << endl;
// 用引用修改元素 for (int &n : nums) { n *= 2; } for (int n : nums) { cout << n << " "; } cout << endl; // 10 20 30 40 return 0;}二、字符串
2.1 C 风格字符串
#include <iostream>#include <cstring>using namespace std;
int main() { // C 风格字符串:以 '\0' 结尾的字符数组 char str1[] = "Hello"; // 自动加 '\0' char str2[] = {'H', 'i', '\0'}; // 手动加 '\0' char str3[20];
// 常用函数 strcpy(str3, "World"); // 复制 strcat(str3, " C++"); // 拼接 cout << "str3 = " << str3 << endl; // World C++ cout << "strlen(str1) = " << strlen(str1) << endl; // 5(不含'\0')
// 比较 if (strcmp(str1, "Hello") == 0) { cout << "相等" << endl; } return 0;}2.2 std::string(推荐)
#include <iostream>#include <string>using namespace std;
int main() { string s1 = "Hello"; string s2 = " C++";
// 拼接 string s3 = s1 + s2; cout << "s3 = " << s3 << endl; // Hello C++
// 长度与访问 cout << "长度: " << s3.length() << endl; // 9 cout << "首字符: " << s3[0] << endl; // H
// 查找 size_t pos = s3.find("C++"); if (pos != string::npos) { cout << "找到 C++ 在位置 " << pos << endl; // 6 }
// 截取子串 string sub = s3.substr(6, 3); cout << "子串: " << sub << endl; // C++
// 比较 if (s1 < s2) { cout << "s1 字典序小于 s2" << endl; } return 0;}2.3 string 与 C 字符串互转
#include <iostream>#include <string>using namespace std;
int main() { // string -> const char* string s = "Hello"; const char *cstr = s.c_str(); cout << "C 字符串: " << cstr << endl;
// const char* -> string const char *p = "World"; string s2 = p; cout << "string: " << s2 << endl; return 0;}三、指针基础
3.1 指针的概念
指针是存储地址的变量:
#include <iostream>using namespace std;
int main() { int num = 42;
// 声明指针并取地址 int *ptr = # // & 取地址,* 声明指针
cout << "num 的值: " << num << endl; // 42 cout << "num 的地址: " << &num << endl; // 如 0x61ff08 cout << "ptr 的值: " << ptr << endl; // 同 num 地址 cout << "ptr 解引用: " << *ptr << endl; // 42
// 通过指针修改值 *ptr = 100; cout << "修改后 num = " << num << endl; // 100 return 0;}3.2 空指针与野指针
#include <iostream>using namespace std;
int main() { int *p1 = nullptr; // C++11 空指针(推荐) int *p2 = NULL; // C 风格(不推荐) int *p3 = 0; // 等价于空指针
if (p1 == nullptr) { cout << "p1 是空指针" << endl; }
// 野指针:未初始化的指针,指向未知地址 int *wild; // 未初始化 // *wild = 10; // 危险!解引用野指针是未定义行为
// 正确做法:使用前必须指向有效内存 int value = 5; int *safe = &value; cout << *safe << endl; // 5 return 0;}3.3 指针的运算
#include <iostream>using namespace std;
int main() { int arr[] = {10, 20, 30, 40};
int *p = arr; // 数组名退化为首元素地址 cout << "*p = " << *p << endl; // 10 cout << "*(p+1) = " << *(p + 1) << endl; // 20(指针+1 跳过 1 个 int) cout << "*(p+2) = " << *(p + 2) << endl; // 30
// 指针算术与下标等价 cout << "p[1] = " << p[1] << endl; // 20 cout << "*(arr+1) = " << *(arr + 1) << endl; // 20
// 遍历 for (int *q = arr; q < arr + 4; q++) { cout << *q << " "; } cout << endl; // 10 20 30 40 return 0;}四、指针与数组的关系
4.1 数组名与指针
#include <iostream>using namespace std;
int main() { int arr[3] = {1, 2, 3};
// 数组名 arr 可视为指向首元素的常量指针 cout << "arr = " << arr << endl; // 首地址 cout << "&arr[0] = " << &arr[0] << endl; // 同首地址 cout << "a[i] == *(a+i): " << (arr[1] == *(arr + 1)) << endl; // 1(相等)
// 数组名不可被赋值(不是真正的变量指针) // arr = &arr[1]; // 错误!
// 但可以用指针指向数组并移动 int *p = arr; p++; // 合法,指针可以移动 cout << "*p = " << *p << endl; // 2 return 0;}4.2 指针作为函数参数(传数组)
#include <iostream>using namespace std;
// 数组参数退化为指针,需要同时传大小int sumArray(int arr[], int size) { int sum = 0; for (int i = 0; i < size; i++) { sum += arr[i]; } return sum;}
// 等价写法:int *arrint sumArrayPtr(int *arr, int size) { int sum = 0; for (int i = 0; i < size; i++) { sum += *(arr + i); } return sum;}
int main() { int scores[] = {85, 90, 78, 92}; cout << "总分 = " << sumArray(scores, 4) << endl; // 345 cout << "总分 = " << sumArrayPtr(scores, 4) << endl; // 345 return 0;}五、引用
5.1 引用基础
#include <iostream>using namespace std;
int main() { int num = 10;
// 引用:变量的别名,必须初始化且不能改绑 int &ref = num; ref = 20; // 通过引用修改原变量
cout << "num = " << num << endl; // 20 cout << "ref = " << ref << endl; // 20
// 引用不是独立变量,修改引用就是修改原变量 int other = 50; ref = other; // 这是把 other 的值赋给 num,不是让 ref 绑定 other cout << "num = " << num << endl; // 50 return 0;}5.2 指针 vs 引用
| 维度 | 指针 | 引用 |
|---|---|---|
| 定义 | 存储地址的变量 | 变量的别名 |
| 初始化 | 可以不初始化(野指针) | 必须初始化 |
| 重新绑定 | 可以指向其他对象 | 不可改变 |
| 空值 | 可以为 nullptr | 不能为空 |
| 语法 | 需要 * 解引用 | 直接使用 |
| 适用 | 动态分配、可选对象、数组遍历 | 函数参数、运算符重载 |
六、const 限定
6.1 顶层 const 与底层 const
#include <iostream>using namespace std;
int main() { int num = 10;
// 顶层 const:指针本身不可变 int *const pTop = # // pTop 不能指向别处 *pTop = 20; // 但可以修改指向的值 cout << "num = " << num << endl; // 20
// 底层 const:指向的对象不可变 const int *pLow = # // 不能通过 pLow 修改值 // *pLow = 30; // 错误! pLow = nullptr; // 但 pLow 可以指向别处
// 同时 const const int *const pBoth = # // pBoth = nullptr; // 错误! // *pBoth = 30; // 错误! return 0;}6.2 const 指针传参惯例
#include <iostream>using namespace std;
// const int* 表示只读访问,不修改数组void printArray(const int arr[], int size) { for (int i = 0; i < size; i++) { cout << arr[i] << " "; } cout << endl; // arr[0] = 99; // 错误!const 数组不可修改}
int main() { int data[] = {1, 2, 3, 4}; printArray(data, 4); // 1 2 3 4 return 0;}七、实战:字符串反转与回文判断
综合本篇知识,实现字符串处理和回文判断:
#include <iostream>#include <string>using namespace std;
// 反转字符串(用指针实现)void reverseStr(char *str) { int len = 0; while (str[len] != '\0') len++; // 求长度
char *left = str; char *right = str + len - 1; while (left < right) { char temp = *left; *left = *right; *right = temp; left++; right--; }}
// 判断回文(用 std::string)bool isPalindrome(const string &s) { int left = 0, right = s.length() - 1; while (left < right) { if (s[left] != s[right]) return false; left++; right--; } return true;}
int main() { // 1. 字符数组反转 char text[] = "HelloWorld"; reverseStr(text); cout << "反转后: " << text << endl; // dlroWolleH
// 2. 回文判断 string words[] = {"level", "hello", "上海自来水来自海上"}; for (const string &w : words) { cout << "\"" << w << "\" " << (isPalindrome(w) ? "是回文" : "不是回文") << endl; } return 0;}运行示例:
反转后: dlroWolleH"level" 是回文"hello" 不是回文"上海自来水来自海上" 是回文总结
本篇讲解了数组(一维/多维/范围 for)、字符串(C 风格与 std::string)、指针基础(地址/解引用/运算/野指针)、指针与数组的关系、引用与指针的区别、const 限定(顶层/底层),并用字符串反转和回文判断串联实战。重点掌握:数组越界的危害、std::string 的常用操作、指针算术、引用与指针的选择。
下一篇将讲解结构体、枚举与类初探,正式进入面向对象世界,敬请期待!
C++入门教程:数组、字符串与指针入门
作者:Wang Shijie
本文链接:https://wsj-blog.pages.dev/posts/c-ru-men-jiao-cheng-shu-zu-zi-fu-chuan-yu-zhi-zhen-ru-men/
本文采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
留言评论
评论资源加载失败,请重试。