C&C++快速入门

11、数组与字符串

1、课程目标

  • 掌握一维和多维数组的定义和使用
  • 理解字符串的存储方式
  • 掌握字符数组与字符指针的区别
  • 了解宽字符和Unicode字符串

2、名词解释

术语 说明
数组 相同类型元素的连续存储集合
索引 访问数组元素的下标,从0开始
字符串 以\0结尾的字符数组
空终止符 \0,标识字符串结束
ANSI 单字节字符编码
Unicode 宽字符编码,Windows使用UTF-16
wchar_t 宽字符类型,Windows上2字节
TCHAR 根据编译选项自动选择char或wchar_t

3、代码实现

1. 一维数组

#include <stdio.h>

int main() {
    printf("=== 一维数组 ===\n\n");
    
    // 数组定义与初始化
    int arr1[5];                       // 未初始化
    int arr2[5] = {1, 2, 3, 4, 5};     // 完全初始化
    int arr3[5] = {1, 2};              // 部分初始化,其余为0
    int arr4[] = {1, 2, 3};            // 自动计算大小
    int arr5[5] = {0};                 // 全部初始化为0
    
    // 数组大小
    printf("【数组大小】\n");
    printf("arr2大小: %d字节\n", (int)sizeof(arr2));
    printf("元素个数: %d\n", (int)(sizeof(arr2)/sizeof(arr2[0])));
    
    // 数组访问
    printf("\n【数组访问】\n");
    for (int i = 0; i < 5; i++) {
        printf("arr2[%d] = %d\n", i, arr2[i]);
    }
    
    // 数组与指针
    printf("\n【数组与指针】\n");
    int* p = arr2;  // 数组名是首元素地址
    printf("arr2 = %p\n", (void*)arr2);
    printf("&arr2[0] = %p\n", (void*)&arr2[0]);
    printf("p = %p\n", (void*)p);
    printf("*p = %d, *(p+1) = %d\n", *p, *(p+1));
    
    return 0;
}

2. 多维数组

#include <stdio.h>

int main() {
    printf("=== 多维数组 ===\n\n");
    
    // 二维数组
    int matrix[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };
    
    printf("【二维数组遍历】\n");
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%3d ", matrix[i][j]);
        }
        printf("\n");
    }
    
    // 内存布局
    printf("\n【内存布局】\n");
    printf("matrix地址: %p\n", (void*)matrix);
    printf("matrix[0]地址: %p\n", (void*)matrix[0]);
    printf("matrix[1]地址: %p\n", (void*)matrix[1]);
    printf("行间隔: %d字节\n", 
           (int)((char*)matrix[1] - (char*)matrix[0]));
    
    return 0;
}

3. 字符串基础

#include <stdio.h>
#include <string.h>

int main() {
    printf("=== 字符串基础 ===\n\n");
    
    // 字符数组 vs 字符串
    char arr1[] = {'H', 'e', 'l', 'l', 'o'};      // 字符数组,非字符串
    char arr2[] = {'H', 'e', 'l', 'l', 'o', '\0'}; // 字符串
    char arr3[] = "Hello";                        // 字符串(自动加\0)
    char* str = "Hello";                          // 字符串指针
    
    printf("【大小对比】\n");
    printf("arr1: %d字节 (无\\0)\n", (int)sizeof(arr1));  // 5
    printf("arr2: %d字节 (有\\0)\n", (int)sizeof(arr2));  // 6
    printf("arr3: %d字节 (有\\0)\n", (int)sizeof(arr3));  // 6
    printf("str:  %d字节 (指针大小)\n", (int)sizeof(str)); // 4或8
    
    printf("\n【字符串长度】\n");
    printf("strlen(arr3): %d\n", (int)strlen(arr3));  // 5
    printf("strlen(str):  %d\n", (int)strlen(str));   // 5
    
    // 字符串修改
    printf("\n【字符串修改】\n");
    arr3[0] = 'h';  // OK: 字符数组可修改
    printf("arr3: %s\n", arr3);
    // str[0] = 'h';  // 错误! 字符串常量不可修改
    
    return 0;
}

4. 宽字符串

#include <stdio.h>
#include <windows.h>
#include <wchar.h>

int main() {
    printf("=== 宽字符串 ===\n\n");
    
    // 宽字符定义
    wchar_t wstr[] = L"Hello世界";  // L前缀表示宽字符
    
    printf("【宽字符大小】\n");
    printf("wchar_t大小: %d字节\n", (int)sizeof(wchar_t));
    printf("wstr数组大小: %d字节\n", (int)sizeof(wstr));
    printf("wstr长度: %d字符\n", (int)wcslen(wstr));
    
    // 打印宽字符串
    wprintf(L"\nwstr: %ls\n", wstr);
    
    // Windows API中的字符串类型
    printf("\n【Windows字符串类型】\n");
    LPSTR ansiStr = "ANSI String";     // char*
    LPWSTR wideStr = L"Wide String";   // wchar_t*
    LPCSTR constAnsi = "Const ANSI";   // const char*
    LPCWSTR constWide = L"Const Wide"; // const wchar_t*
    
    printf("LPSTR: %s\n", ansiStr);
    wprintf(L"LPWSTR: %ls\n", wideStr);
    
    return 0;
}

5、课后作业

5.1、作业1:数组操作

实现一个函数,将数组元素反转。

5.2、作业2:字符串复制

手动实现strcpy函数,注意处理\0。

5.3、作业3:ANSI转Unicode

使用MultiByteToWideChar实现ANSI到Unicode转换。