C语言指针专题二 -- 字符指针与字符串

目录

1. 字符指针与字符串的核心原理

字符串的本质

字符串的存储

字符指针的特性

字符指针的操作 

2. 编程实例

3. 常见陷阱与注意事项

4. 总结


1. 字符指针与字符串的核心原理

字符串的本质

  • C语言中没有独立的字符串类型,字符串本质是 \0(空字符)结尾的字符数组

  • 字符串的存储方式:

    • 字符数组:显式声明数组并初始化,如 char str[] = "Hello";

    • 字符指针:直接指向字符串字面量(存储在程序的只读内存区),如 char *p = "Hello";

字符串的存储

在C语言中,字符串是以字符数组的形式存储的,并以空字符 \0 作为字符串的结束标志。下面通过文字描述和图示来解释C语言中的字符串存储规则。

假设有一个简单的字符串 "Hello",在内存中的存储形式如下:

地址    内存内容
-----------------
1000    'H' (72)
1001    'e' (101)
1002    'l' (108)
1003    'l' (108)
1004    'o' (111)
1005    '\0' (0)  // 字符串结束标志
  • 每个字符都占用一个字节的存储空间。
  • '\0' 是字符串的结束标记,它告诉程序这个位置之前的所有字符属于当前字符串。
  • 注意这里的地址(如1000)只是示意性的,实际的内存地址会根据系统分配情况有所不同。

图例表示
如果我们用图形的方式表示上述 "Hello" 字符串在内存中的存储方式,可以想象成如下布局:

+--------+--------+--------+--------+--------+--------+
| 1000   | 1001   | 1002   | 1003   | 1004   | 1005   |
+--------+--------+--------+--------+--------+--------+
| 'H'    | 'e'    | 'l'    | 'l'    | 'o'    | '\0'   |
+--------+--------+--------+--------+--------+--------+

每个方格代表一个字节的内存单元,里面存放的是相应字符的ASCII码值。例如,'H' 的ASCII码是72,但在内存表示中我们通常直接写字符本身而不是其ASCII码值,以便于理解和记忆。

字符指针的特性

  • 指向字符串字面量:字符指针可以指向字符串常量(只读内存区),但不可修改其内容。

    char *p = "Hello"; // p指向只读内存区的字符串
    // p[0] = 'h';     // 错误!尝试修改只读内存会导致崩溃
  • 指向字符数组:字符指针可以指向动态分配的或栈上的字符数组,此时可修改内容。
    char arr[] = "Hello";
    char *p = arr;     // p指向栈上的字符数组
    p[0] = 'h';        // 合法!修改栈内存

字符指针的操作 

  • 遍历字符串:通过指针移动逐个访问字符,直到遇到\0。
  • 动态内存分配:使用malloc为字符串动态分配内存,需手动释放。
  • 字符串函数:C标准库提供中的函数(如strcpy、strlen),底层均依赖指针操作。

2. 编程实例

实例1:字符指针与字符串初始化

#include 

int main() {
    // 方式1:字符指针指向字符串字面量(只读)
    char *str1 = "Hello";
    printf("str1: %s\n", str1); // 输出: Hello

    // 方式2:字符数组(可修改)
    char str2[] = "World";
    char *p = str2;           // 指针指向字符数组
    p[0] = 'w';               // 修改第一个字符
    printf("str2: %s\n", p);  // 输出: world

    return 0;
}

实例2:动态分配字符串内存

#include 
#include 
#include 

int main() {
    // 动态分配内存存储字符串
    char *str = (char*)malloc(20 * sizeof(char));
    if (str == NULL) {
        printf("内存分配失败!\n");
        return 1;
    }

    strcpy(str, "Dynamic");  // 复制字符串到堆内存
    printf("初始内容: %s\n", str); // 输出: Dynamic

    strcat(str, "123");      // 追加字符串
    printf("追加后内容: %s\n", str); // 输出: Dynamic123

    free(str);  // 释放内存
    str = NULL; // 避免野指针

    return 0;
}

实例3:字符指针遍历字符串

#include 

void print_string(const char *str) {
    while (*str != '\0') {  // 遍历直到空字符
        printf("%c ", *str);
        str++;              // 指针后移
    }
    printf("\n");
}

int main() {
    char *s = "Pointer";
    print_string(s);  // 输出: P o i n t e r 
    return 0;
}

 实例4:修改字符指针指向的内容

#include 

int main() {
    char arr[] = "Hello";  // 栈上的字符数组
    char *p1 = arr;        // 指向可修改的数组
    p1[0] = 'h';           // 合法修改
    printf("p1: %s\n", p1); // 输出: hello

    char *p2 = "Hello";    // 指向只读内存的字符串字面量
    // p2[0] = 'h';        // 运行时错误(段错误)!
    printf("p2: %s\n", p2);

    return 0;
}

 实例5:字符串作为函数参数(指针传递)

#include 

// 函数:统计字符串长度(手动实现strlen)
int string_length(const char *str) {
    int len = 0;
    while (*str != '\0') {
        len++;
        str++;
    }
    return len;
}

int main() {
    char *s = "C Programming";
    printf("字符串长度: %d\n", string_length(s)); // 输出: 13
    return 0;
}

3. 常见陷阱与注意事项

1. 修改只读字符串

char *p = "Hello";
p[0] = 'h';  // 段错误!字符串字面量不可修改。

 2. 未分配内存直接使用指针

char *p;
strcpy(p, "Hello");  // 野指针!p未初始化指向合法内存。

3. 忘记字符串终止符\0

char arr[5] = {'H', 'e', 'l', 'l', 'o'}; // 缺少\0,遍历时可能越界
printf("%s", arr);  // 输出可能包含乱码

4. 内存泄漏

char *str = malloc(100);
// 忘记调用 free(str);

4. 总结

  • 字符指针是操作字符串的核心工具,灵活但需谨慎使用。

  • 字符串字面量存储在只读内存区,字符指针指向时不可修改。

  • 字符数组(栈或堆内存)可通过指针修改内容。

  • 动态分配字符串内存时,必须手动管理生命周期(malloc/free)。

  • 始终确保字符串以\0结尾,避免越界访问。

你可能感兴趣的:(c语言,开发语言,数据结构)