char与string类型在C语言中到底有何区别?

99ANYc3cd6
预计阅读时长 19 分钟
位置: 首页 C语言 正文

这是一个非常核心且重要的概念,因为 C 语言本身并没有一个叫做 string 的原生类型,我们通常所说的 "字符串" 在 C 语言中是通过 字符数组 来实现的。

c语言char string类型
(图片来源网络,侵删)

char 类型:单个字符

char 是 C 语言的一个基本数据类型,用来存储一个单一的字符。

特点:

  • 大小:通常是 1 字节(8 位)。
  • 存储:它存储的是字符的 ASCII 码值(一个整数),而不是字符本身,字符 'A' 在内存中存储的是整数 65
  • 声明和初始化
    char c1 = 'A'; // 使用单引号,表示一个字符
    char c2 = 65;  // 直接使用 ASCII 码值,效果等同于 'A'
    char c3 = '\n'; // 特殊字符,如换行符

错误示范:

char c4 = "A"; // 错误!双引号 "..." 表示字符串,会包含一个 '\0' 结尾符,类型不匹配

C 语言中的 "字符串" (string)

如前所述,C 语言没有 string 类型,字符串被实现为以 空字符 ('\0') 结尾的字符数组。

核心概念:字符串的结尾

C 语言用 空字符 ('\0') 来标记一个字符串的结束,这个字符的 ASCII 码值是 0,任何以 '\0' 结尾的字符序列,C 语言都将其视为一个字符串。

如何表示和创建字符串

主要有三种方式:

c语言char string类型
(图片来源网络,侵删)

字符数组

这是最基本的方式,你需要手动确保数组末尾有一个 '\0'

// 方式 1a:定义时初始化,编译器会自动添加 '\0'
char str1[] = "Hello"; 
// 内存布局: ['H', 'e', 'l', 'l', 'o', '\0']
// sizeof(str1) 是 6,因为包含了 '\0'
// 方式 1b:先定义,再逐个赋值
char str2[6]; // 必须预留一个位置给 '\0'
str2[0] = 'H';
str2[1] = 'e';
str2[2] = 'l';
str2[3] = 'l';
str2[4] = 'o';
str2[5] = '\0'; // 必须手动添加结尾符!
// 方式 1c:使用循环赋值
char str3[10];
for (int i = 0; i < 5; i++) {
    str3[i] = "Hello"[i]; // "Hello" 是一个常量字符串
}
str3[5] = '\0'; // 仍然需要手动添加

字符指针

字符指针指向字符串的第一个字符(通常是字符串字面量的首地址)。

// 方式 2a:指向一个字符串字面量
// "Hello" 存储在程序的只读数据区,str4 指向它的第一个字符 'H'
char *str4 = "Hello"; 
// 内存布局: str4 -> ['H', 'e', 'l', 'l', 'o', '\0'] (在只读区)
// 重要区别:
// char str5[] = "Hello";  // str5 是一个可修改的数组
// char *str6 = "Hello";  // str6 是一个指向只读内存的指针,不建议修改其指向的内容
// str6[0] = 'h'; // 这可能导致未定义行为(程序崩溃),因为它试图修改只读内存
// 方式 2b:动态分配内存
char *str7 = (char *)malloc(6 * sizeof(char));
if (str7 != NULL) {
    strcpy(str7, "Hello"); // 使用 strcpy 函数来安全地复制字符串
    // str7 现在指向一块堆内存,内容是 "Hello"
}
// ... 使用 str7 ...
free(str7); // 记得释放内存

使用 string.h 中的函数处理

<string.h> 头文件提供了大量专门用于处理 C 风格字符串的函数,如 strlen, strcpy, strcat, strcmp 等。

  • strlen(str):返回字符串的长度(不包括结尾的 '\0')。
  • strcpy(dest, src):将 src 字符串复制到 dest 中。dest 必须有足够的空间。
  • strcat(dest, src):将 src 字符串连接到 dest 的末尾。dest 必须有足够的空间。
  • strcmp(s1, s2):比较两个字符串,如果相等,返回 0s1 小于 s2,返回负数;否则返回正数。

示例:

c语言char string类型
(图片来源网络,侵删)
#include <stdio.h>
#include <string.h> // 必须包含此头文件
int main() {
    char greeting[50] = "Hello, "; // 预留足够空间用于连接
    char name[] = "World";
    // 获取长度
    printf("Length of 'name': %zu\n", strlen(name)); // 使用 %zu 打印 size_t 类型
    // 连接字符串
    strcat(greeting, name);
    printf("After strcat: %s\n", greeting); // 输出: Hello, World
    // 复制字符串
    char copy_str[20];
    strcpy(copy_str, greeting);
    printf("Copied string: %s\n", copy_str); // 输出: Hello, World
    // 比较字符串
    if (strcmp(greeting, copy_str) == 0) {
        printf("The strings are equal.\n");
    }
    return 0;
}

char 数组 vs. char * 指针(关键区别)

这是 C 语言初学者最容易混淆的地方,虽然它们在很多情况下可以互换使用,但本质和用法有重要区别。

特性 char name[] (字符数组) char *name (字符指针)
本质 一块连续的、固定大小的内存空间,用于存放字符。 一个变量,它存储的是字符串的首地址
内存位置 通常在上分配。 可以指向只读数据区上的内存。
大小 sizeof(name) 返回数组总大小(包括 '\0')。 sizeof(name) 返回指针变量本身的大小(在 64 位系统上是 8 字节)。
可修改性 可修改的(只要不越界)。 如果指向字符串字面量,其内容通常不可修改(只读区),如果指向堆内存,则可修改。
可变性 不可改变指向的地址。name 是一个常量指针。 可以改变指向的地址。name 是一个变量指针。

示例代码对比:

#include <stdio.h>
#include <string.h>
int main() {
    // 1. 字符数组
    char arr[] = "Hello";
    printf("Array: sizeof(arr) = %zu\n", sizeof(arr)); // 输出 6
    // arr = "World"; // 错误!不能给数组重新赋值
    strcpy(arr, "World"); // 正确!可以修改数组内容
    printf("Array after strcpy: %s\n", arr);
    // 2. 字符指针
    char *ptr = "Hello";
    printf("Pointer: sizeof(ptr) = %zu\n", sizeof(ptr)); // 输出 8 (64位系统)
    // ptr[0] = 'h'; // 危险!可能导致段错误,因为 "Hello" 在只读区
    ptr = "World";    // 正确!可以改变指针指向的地址
    printf("Pointer after re-assignment: %s\n", ptr);
    return 0;
}

安全性:缓冲区溢出

由于 C 语言不进行边界检查,直接使用 strcpy, gets, scanf 等函数处理字符串非常危险,容易导致缓冲区溢出,从而引发程序崩溃或安全漏洞。

不安全的例子:

#include <stdio.h>
#include <string.h>
int main() {
    char buffer[10];
    printf("Enter a long string (e.g., > 10 chars): ");
    // gets(buffer); // gets 函数极度危险,已被废弃,因为它不检查缓冲区大小
    // scanf("%s", buffer); // scanf 也同样危险,遇到空格就停止,但不会检查长度
    // 一个更安全的替代方案
    fgets(buffer, sizeof(buffer), stdin);
    // fgets 会读取最多 sizeof(buffer)-1 个字符,并自动添加 '\0'
    // 但要注意,fgets 会保留换行符 '\n'
    printf("You entered: %s\n", buffer);
    return 0;
}

现代 C 编程建议:

  • 优先使用 fgets 替代 getsscanf 来读取输入。
  • 使用 strncpy 替代 strcpy,可以指定最大复制长度。
  • 使用 snprintf 替代 sprintf,可以指定最大写入长度。
  • 考虑使用更安全的 C 库,如 Microsoft's Safe C Runtime Library 或第三方库。

  1. char:用于存储单个字符,本质是 1 字节的整数。
  2. C 字符串:不是一个独立类型,而是以 '\0' 结尾的 char 数组
  3. 两种主要形式
    • 字符数组 (char str[]):固定大小,内容可修改,地址不可改,在栈上。
    • 字符指针 (char *str):可变地址,指向字符串(可能在只读区或堆上)。
  4. <string.h>:是处理 C 字符串的标准库,提供了丰富的函数。
  5. 安全性:C 字符串操作是不安全的,极易发生缓冲区溢出,必须使用有边界检查的函数(如 fgets, strncpy)并时刻注意数组的大小。
-- 展开阅读全文 --
头像
织梦content list
« 上一篇 2025-12-23
Server2003如何搭建DedeCMS?
下一篇 » 2025-12-23

相关文章

取消
微信二维码
支付宝二维码

目录[+]