Skip to content

数组与字符串

数组和字符串是 C 语言中最常用的数据结构。

一维数组

数组声明与初始化

c
#include <stdio.h>

int main() {
    // 声明数组
    int arr1[5];  // 声明但不初始化(值不确定)
    
    // 完全初始化
    int arr2[5] = {1, 2, 3, 4, 5};
    
    // 部分初始化(其余为0)
    int arr3[5] = {1, 2};  // {1, 2, 0, 0, 0}
    
    // 自动推断大小
    int arr4[] = {1, 2, 3, 4, 5};  // 大小为5
    
    // 全部初始化为0
    int arr5[5] = {0};  // {0, 0, 0, 0, 0}
    
    // 指定初始化器 (C99)
    int arr6[10] = {[0] = 1, [5] = 2, [9] = 3};
    
    // 访问元素
    printf("arr2[0] = %d\n", arr2[0]);
    printf("arr2[4] = %d\n", arr2[4]);
    
    // 修改元素
    arr2[0] = 10;
    
    // 数组大小
    printf("数组大小: %zu bytes\n", sizeof(arr2));
    printf("元素个数: %zu\n", sizeof(arr2) / sizeof(arr2[0]));
    
    return 0;
}

数组遍历

c
#include <stdio.h>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int size = sizeof(arr) / sizeof(arr[0]);
    
    // 使用索引遍历
    printf("索引遍历:\n");
    for (int i = 0; i < size; i++) {
        printf("arr[%d] = %d\n", i, arr[i]);
    }
    
    // 使用指针遍历
    printf("\n指针遍历:\n");
    int *p = arr;
    for (int i = 0; i < size; i++) {
        printf("*(p + %d) = %d\n", i, *(p + i));
    }
    
    // 指针递增遍历
    printf("\n指针递增遍历:\n");
    int *end = arr + size;
    for (int *p = arr; p < end; p++) {
        printf("%d ", *p);
    }
    printf("\n");
    
    return 0;
}

数组作为函数参数

c
#include <stdio.h>

// 数组作为参数(退化为指针)
void print_array(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

// 等价写法
void print_array2(int *arr, int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

// 计算数组元素和
int sum_array(int arr[], int size) {
    int sum = 0;
    for (int i = 0; i < size; i++) {
        sum += arr[i];
    }
    return sum;
}

// 修改数组元素
void double_array(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        arr[i] *= 2;
    }
}

int main() {
    int arr[] = {1, 2, 3, 4, 5};
    int size = sizeof(arr) / sizeof(arr[0]);
    
    printf("原数组: ");
    print_array(arr, size);
    
    printf("和: %d\n", sum_array(arr, size));
    
    double_array(arr, size);
    printf("翻倍后: ");
    print_array(arr, size);
    
    return 0;
}

多维数组

二维数组

c
#include <stdio.h>

int main() {
    // 声明与初始化
    int matrix[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };
    
    // 部分初始化
    int m2[3][4] = {
        {1, 2},
        {5},
        {9, 10, 11}
    };
    
    // 省略内层大括号
    int m3[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
    
    // 访问元素
    printf("matrix[0][0] = %d\n", matrix[0][0]);
    printf("matrix[1][2] = %d\n", matrix[1][2]);
    
    // 遍历二维数组
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%2d ", matrix[i][j]);
        }
        printf("\n");
    }
    
    // 行数和列数
    int rows = sizeof(matrix) / sizeof(matrix[0]);
    int cols = sizeof(matrix[0]) / sizeof(matrix[0][0]);
    printf("行数: %d, 列数: %d\n", rows, cols);
    
    return 0;
}

二维数组作为参数

c
#include <stdio.h>

// 必须指定列数
void print_matrix(int rows, int cols, int matrix[][cols]) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%2d ", matrix[i][j]);
        }
        printf("\n");
    }
}

// 使用指针
void print_matrix_ptr(int rows, int cols, int *matrix) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%2d ", *(matrix + i * cols + j));
        }
        printf("\n");
    }
}

int main() {
    int matrix[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };
    
    print_matrix(3, 4, matrix);
    printf("\n");
    print_matrix_ptr(3, 4, (int*)matrix);
    
    return 0;
}

三维数组

c
#include <stdio.h>

int main() {
    // 三维数组
    int cube[2][3][4] = {
        {
            {1, 2, 3, 4},
            {5, 6, 7, 8},
            {9, 10, 11, 12}
        },
        {
            {13, 14, 15, 16},
            {17, 18, 19, 20},
            {21, 22, 23, 24}
        }
    };
    
    // 遍历
    for (int i = 0; i < 2; i++) {
        printf("第 %d 层:\n", i);
        for (int j = 0; j < 3; j++) {
            for (int k = 0; k < 4; k++) {
                printf("%2d ", cube[i][j][k]);
            }
            printf("\n");
        }
        printf("\n");
    }
    
    return 0;
}

字符串

字符串基础

c
#include <stdio.h>

int main() {
    // 字符数组(可修改)
    char str1[] = "Hello";
    str1[0] = 'h';  // 可以修改
    printf("str1: %s\n", str1);
    
    // 字符串常量指针(不可修改)
    char *str2 = "World";
    // str2[0] = 'w';  // 未定义行为
    printf("str2: %s\n", str2);
    
    // 字符数组初始化
    char str3[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
    char str4[6] = "Hello";
    
    // 字符串长度
    printf("str1 长度: %zu\n", sizeof(str1));  // 6(包含 '\0')
    printf("str1 字符数: %zu\n", strlen(str1));  // 5
    
    // 遍历字符串
    char *p = str1;
    while (*p != '\0') {
        printf("%c ", *p);
        p++;
    }
    printf("\n");
    
    return 0;
}

字符串输入输出

c
#include <stdio.h>

int main() {
    char name[50];
    
    // scanf 读取(遇到空格停止)
    printf("请输入名字(不含空格): ");
    scanf("%s", name);
    printf("名字: %s\n", name);
    
    // 清除输入缓冲区
    while (getchar() != '\n');
    
    // fgets 读取一行(推荐)
    printf("请输入完整名字: ");
    fgets(name, sizeof(name), stdin);
    // 去除末尾换行符
    name[strcspn(name, "\n")] = '\0';
    printf("名字: %s\n", name);
    
    // puts 输出字符串
    puts("使用 puts 输出");
    
    // fputs 输出到文件或 stdout
    fputs("使用 fputs 输出\n", stdout);
    
    return 0;
}

字符串函数

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

int main() {
    char str1[50] = "Hello";
    char str2[50] = "World";
    char str3[50];
    
    // 字符串长度
    printf("strlen(str1) = %zu\n", strlen(str1));
    
    // 字符串复制
    strcpy(str3, str1);
    printf("strcpy: %s\n", str3);
    
    // 字符串连接
    strcat(str1, " ");
    strcat(str1, str2);
    printf("strcat: %s\n", str1);
    
    // 字符串比较
    char s1[] = "apple";
    char s2[] = "banana";
    printf("strcmp(s1, s2) = %d\n", strcmp(s1, s2));  // -1
    printf("strcmp(s2, s1) = %d\n", strcmp(s2, s1));  // 1
    printf("strcmp(s1, s1) = %d\n", strcmp(s1, s1));  // 0
    
    // 字符串查找
    char str[] = "Hello, World!";
    char *pos = strchr(str, 'W');
    if (pos != NULL) {
        printf("找到 'W' 在位置: %ld\n", pos - str);
    }
    
    pos = strstr(str, "World");
    if (pos != NULL) {
        printf("找到 \"World\" 在位置: %ld\n", pos - str);
    }
    
    // 安全版本(推荐)
    char dest[10];
    strncpy(dest, "Hello World", sizeof(dest) - 1);
    dest[sizeof(dest) - 1] = '\0';
    printf("strncpy: %s\n", dest);
    
    return 0;
}

自定义字符串函数

c
#include <stdio.h>

// 字符串长度
size_t my_strlen(const char *str) {
    const char *p = str;
    while (*p) p++;
    return p - str;
}

// 字符串复制
char* my_strcpy(char *dest, const char *src) {
    char *p = dest;
    while ((*p++ = *src++));
    return dest;
}

// 字符串连接
char* my_strcat(char *dest, const char *src) {
    char *p = dest;
    while (*p) p++;
    while ((*p++ = *src++));
    return dest;
}

// 字符串比较
int my_strcmp(const char *s1, const char *s2) {
    while (*s1 && (*s1 == *s2)) {
        s1++;
        s2++;
    }
    return *(unsigned char*)s1 - *(unsigned char*)s2;
}

// 字符串查找
char* my_strchr(const char *str, int c) {
    while (*str && *str != c) {
        str++;
    }
    return (*str == c) ? (char*)str : NULL;
}

int main() {
    char s1[50] = "Hello";
    char s2[50] = "World";
    
    printf("长度: %zu\n", my_strlen(s1));
    
    char s3[50];
    my_strcpy(s3, s1);
    printf("复制: %s\n", s3);
    
    my_strcat(s3, " ");
    my_strcat(s3, s2);
    printf("连接: %s\n", s3);
    
    printf("比较: %d\n", my_strcmp("apple", "banana"));
    
    char *pos = my_strchr("Hello", 'l');
    printf("查找: %s\n", pos ? pos : "未找到");
    
    return 0;
}

字符串数组

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

int main() {
    // 二维字符数组
    char fruits[][20] = {
        "Apple",
        "Banana",
        "Cherry",
        "Date"
    };
    
    printf("水果列表:\n");
    for (int i = 0; i < 4; i++) {
        printf("%s\n", fruits[i]);
    }
    
    // 指针数组
    char *colors[] = {
        "Red",
        "Green",
        "Blue",
        "Yellow"
    };
    
    printf("\n颜色列表:\n");
    for (int i = 0; i < 4; i++) {
        printf("%s\n", colors[i]);
    }
    
    // 排序字符串
    char *names[] = {"Charlie", "Alice", "David", "Bob"};
    int n = 4;
    
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            if (strcmp(names[j], names[j + 1]) > 0) {
                char *temp = names[j];
                names[j] = names[j + 1];
                names[j + 1] = temp;
            }
        }
    }
    
    printf("\n排序后:\n");
    for (int i = 0; i < n; i++) {
        printf("%s\n", names[i]);
    }
    
    return 0;
}

字符处理

字符分类函数

c
#include <stdio.h>
#include <ctype.h>

int main() {
    char c;
    
    printf("输入一个字符: ");
    scanf("%c", &c);
    
    // 字符分类
    printf("isalpha: %d\n", isalpha(c));   // 是否字母
    printf("isdigit: %d\n", isdigit(c));   // 是否数字
    printf("isalnum: %d\n", isalnum(c));   // 是否字母或数字
    printf("islower: %d\n", islower(c));   // 是否小写
    printf("isupper: %d\n", isupper(c));   // 是否大写
    printf("isspace: %d\n", isspace(c));   // 是否空白
    printf("ispunct: %d\n", ispunct(c));   // 是否标点
    printf("isxdigit: %d\n", isxdigit(c)); // 是否十六进制数字
    
    // 字符转换
    printf("tolower: %c\n", tolower(c));   // 转小写
    printf("toupper: %c\n", toupper(c));   // 转大写
    
    return 0;
}

字符串转换

c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

int main() {
    // 字符串转数字
    char num_str[] = "12345";
    int num = atoi(num_str);
    long lng = atol("1234567890");
    double dbl = atof("3.14159");
    
    printf("atoi: %d\n", num);
    printf("atol: %ld\n", lng);
    printf("atof: %f\n", dbl);
    
    // 更安全的转换
    char *end;
    long val = strtol("12345abc", &end, 10);
    printf("strtol: %ld, 剩余: %s\n", val, end);
    
    double d = strtod("3.14abc", &end);
    printf("strtod: %f, 剩余: %s\n", d, end);
    
    // 数字转字符串
    char buffer[50];
    sprintf(buffer, "%d", 12345);
    printf("sprintf: %s\n", buffer);
    
    // 字符串大小写转换
    char str[] = "Hello World";
    printf("原字符串: %s\n", str);
    
    // 转大写
    for (int i = 0; str[i]; i++) {
        str[i] = toupper(str[i]);
    }
    printf("大写: %s\n", str);
    
    // 转小写
    for (int i = 0; str[i]; i++) {
        str[i] = tolower(str[i]);
    }
    printf("小写: %s\n", str);
    
    return 0;
}

实践示例

字符串分割

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

int main() {
    char str[] = "apple,banana,cherry,date";
    char *token;
    char *rest = str;
    
    printf("分割字符串:\n");
    while ((token = strtok_r(rest, ",", &rest))) {
        printf("%s\n", token);
    }
    
    // 使用 strtok(会修改原字符串)
    char str2[] = "one two three four";
    token = strtok(str2, " ");
    while (token != NULL) {
        printf("%s\n", token);
        token = strtok(NULL, " ");
    }
    
    return 0;
}

字符串反转

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

void reverse_string(char *str) {
    int len = strlen(str);
    for (int i = 0; i < len / 2; i++) {
        char temp = str[i];
        str[i] = str[len - 1 - i];
        str[len - 1 - i] = temp;
    }
}

int main() {
    char str[] = "Hello World";
    printf("原字符串: %s\n", str);
    
    reverse_string(str);
    printf("反转后: %s\n", str);
    
    return 0;
}

单词统计

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

typedef struct {
    int chars;
    int words;
    int lines;
} TextStats;

TextStats count_text(const char *text) {
    TextStats stats = {0, 0, 0};
    int in_word = 0;
    
    for (int i = 0; text[i] != '\0'; i++) {
        stats.chars++;
        
        if (text[i] == '\n') {
            stats.lines++;
        }
        
        if (isalpha(text[i])) {
            if (!in_word) {
                stats.words++;
                in_word = 1;
            }
        } else {
            in_word = 0;
        }
    }
    
    if (stats.chars > 0 && text[stats.chars - 1] != '\n') {
        stats.lines++;
    }
    
    return stats;
}

int main() {
    char text[] = "Hello World\nThis is a test\nC programming";
    
    TextStats stats = count_text(text);
    
    printf("字符数: %d\n", stats.chars);
    printf("单词数: %d\n", stats.words);
    printf("行数: %d\n", stats.lines);
    
    return 0;
}

矩阵运算

c
#include <stdio.h>

#define ROWS 3
#define COLS 3

void print_matrix(int matrix[ROWS][COLS]) {
    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            printf("%3d ", matrix[i][j]);
        }
        printf("\n");
    }
}

void add_matrices(int a[ROWS][COLS], int b[ROWS][COLS], int result[ROWS][COLS]) {
    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            result[i][j] = a[i][j] + b[i][j];
        }
    }
}

void multiply_matrices(int a[ROWS][COLS], int b[ROWS][COLS], int result[ROWS][COLS]) {
    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            result[i][j] = 0;
            for (int k = 0; k < COLS; k++) {
                result[i][j] += a[i][k] * b[k][j];
            }
        }
    }
}

void transpose_matrix(int matrix[ROWS][COLS], int result[COLS][ROWS]) {
    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            result[j][i] = matrix[i][j];
        }
    }
}

int main() {
    int a[ROWS][COLS] = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };
    
    int b[ROWS][COLS] = {
        {9, 8, 7},
        {6, 5, 4},
        {3, 2, 1}
    };
    
    int result[ROWS][COLS];
    
    printf("矩阵 A:\n");
    print_matrix(a);
    
    printf("\n矩阵 B:\n");
    print_matrix(b);
    
    printf("\nA + B:\n");
    add_matrices(a, b, result);
    print_matrix(result);
    
    printf("\nA * B:\n");
    multiply_matrices(a, b, result);
    print_matrix(result);
    
    printf("\nA 的转置:\n");
    transpose_matrix(a, result);
    print_matrix(result);
    
    return 0;
}