欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

字符串与字符数组、sizeof与strlen

程序员文章站 2022-07-13 17:31:02
...

一、C语言的字符串类型

C语言没有原生的字符串类型,不像C#等高级语言中具有string类型来表示字符串,C语言中的字符串是通过字符指针来间接实现的,如:

char *p = "WHUT2018";

此时p就叫做字符串,但是实际上p只是一个字符指针(本质上就是一个指针变量,只是p指向了一个字符串的起始地址而已)

1.1 C语言中字符串的本质

  1. 字符串就是指针指向的一段连续的内存空间,在内存中就是多个字节连续分布构成的
  2. 字符串就是一串字符,字符在编程语言中就是字符类型的变量。C语言用ASCII编码对字符进行编程,编码后可以用char型变量来表示一个字符。字符串就是多个字符打包在一起构成的。

1.2 C语言中字符串的三个核心要点

  1. 用一个指针指向字符串头
  2. 固定尾部:以’\0’结尾
  3. 组成字符串的各字符彼此地址相连

1.3 关于’\0’

  1. 0'\0'是等价的,48'0'是等价的
  2. '\0'是字符串中的一个魔数(一些具有特殊含义的内容,在这里起结尾的标识作用),因此C语言中无法定义出中间内容含有'\0'的字符串

1.4 指向字符串的指针和字符串本身

指向字符串的指针和字符串本身是分开的两个东西:在下述代码段中

char *p = "WHUT2018";
  1. p是一个字符指针,分配在栈上,占4字节,用来指向字符串,是字符串的引子,但其本身并不是字符串的内容;
  2. "WHUT2018"分配在代码段,占9个字节,其中:
  • 8字节的空间用来存放"WHUT2018"8个字符组成的字符串
  • 1个字节的内存空间存放'\0'这个字符串结束标志(本质上也不是字符串的内容)

1.5 存储多个连续字符的两种方式:

  1. 字符串
  2. 字符数组

二、字符串和字符数组

2.1 sizeof

  1. sizeofC语言中的一个关键字,也是一个运算符,不是函数。
  2. sizeof运算符用来返回一个类型或者变量所占用的内存直接数。
  3. sizeof存在的意义:
  • ADT占几个字节和平台有关
  • UDT无法一眼看出占几个字节

2.2 strlen

  1. strlen是一个C语言库函数,其原型是:size_t strlen(const char *s);
  2. 这个函数接收一个字符串的指针,返回这个字符串的长度(以字节为单位)
  3. strlen返回的字符串长度不包含字符串结尾的'\0'

2.3 字符数组的初始化

字符数组有以下三种初始化的方式,其中方式1是最为方便常用

1. char str1[] = "WHUT2018";
2. char str2[] = {"WHUT2018"};
3. char str3[] = {'W','H','U','T','2','0','1','8','\0'};

测试代码

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

int main(void)
{
    char str0[9];
    char str1[]   = "WHUT2018";
    char str2[8]  = "WHUT2018";
    char str3[4]  = "WHUT2018";
    char str4[15] = "WHUT2018";

    printf("sizeof(str0) = %ld\n", sizeof(str0));
    printf("strlen(str0) = %ld\n", strlen(str0));
    printf("sizeof(str1) = %ld\n", sizeof(str1));
    printf("strlen(str1) = %ld\n", strlen(str1));
    printf("sizeof(str2) = %ld\n", sizeof(str2));
    printf("strlen(str2) = %ld\n", strlen(str2));
    printf("sizeof(str3) = %ld\n", sizeof(str3));
    printf("strlen(str3) = %ld\n", strlen(str3));
    printf("sizeof(str4) = %ld\n", sizeof(str4));
    printf("strlen(str4) = %ld\n", strlen(str4));

    return 0;
}

结果分析

字符串与字符数组、sizeof与strlen

  1. 我们在编译的过程中会看到这样一个警告:
warning: initializer-string for array of chars is too long
     char str3[4] = "WHUT2018";

也就是说字符数组太短,后面的字符太长了。遇到这种情况,编译器会自动截断后面的部分。sizeof(str3) = 4是好理解的,那为什么strlen(str3) = 12 呢?其实这个值是随机的,strlen计算长度的时候是从首地址的字符开始,一直计数到'\0'的位置,所以这个值具体为多少得看栈的情况(栈内存是脏的),同理strlen(0)和strlen(str2)的值也是随机的。

  1. sizeof(arr)得到的永远是字符数组中字符元素的个数(也就是数组的大小),和数组是否初始化、初始化多少是没有关系的。

2.4 字符串初始化

就只有一种方法,直接看测试代码:

测试代码

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

int main(void)
{
    char *p = "WHUT2018";

    printf("sizeof(p) = %ld\n", sizeof(p));
    printf("strlen(p) = %ld\n", strlen(p));

    return 0;
}

测试结果

字符串与字符数组、sizeof与strlen

  • 64位处理器上64位操作系统上的64位编译器的环境下,sizeof(p)得到的永远是8(其他环境永远是4),因为sizeof(p)测的是字符指针p的字节数;
  • strlen才是真正测的字符串的长度(不包括'\0'

2.5 字符串与字符数组的比较

字符数组与字符串的本质差异

  1. 对字符数组char a[] = "WHUT2018";来说,就相当于定义了一个数组aa9个字节,分配在栈上。右值"WHUT2018"本身只存在于编译器中,编译器将他用来初始化字符数组a后丢弃掉(也就是说内存中并没有"WHUT2018"这个字符串的)。就相当于是:
char a[] = {'W', 'H', 'U', 'T', '2', '0', '1', '8', '\0'};
  1. 字符串char *p = "WHUT2018";定义了一个分配在栈上占4(或8)个字节的字符指针p和一个分配在代码段的占9个字节的字符串常量"WHUT2018",然后把代码段中的字符串的首地址赋值给p

字符串与字符数组的选用

通过上述对比我们可以看出字符串和字符数组有本质区别:

  • 字符数组本身自带内存空间,可以用来存储字符。
  • 字符串本身是指针,占4个字节的内存空间,这4个字节用来存储有效数据的首地址。

在工程领域上广泛使用的是字符串,因为字符串的存储地方非常灵活,如下所示:

#include <stdio.h>
#include <stdlib.h>
char str0[10];
int main(void)
{
    /*储存在bss段*/
    char *p1 = str0;
    /*存储在.text段*/
    char *str1 = "WHUT2018";
    /*存储在stack上*/
    char str2[10];
    char *p2 = str2;
    /*储存在heap上*/
    char *str3 = (char *)malloc(16);
    if(!str3)
    {
        printf("MALLOC ERROR!\n");
        return -1;
    }
    free(str3);
    str3 = NULL;
    return 0;
}

测试结果从略

相关标签: C高级学习笔记