GuoXin Li's Blog

C语言字符串浅析 Character String (C)

字数统计: 1.4k阅读时长: 5 min
2019/03/20 Share

字符串

[TOC]

字符串常量

image-20190319154158992

字符串是选择用指针,还是用数组?

image-20190319154450037

字符串字面量

首先字符串字面量是一对双引号括起来的字符序列

延续字符串字面量

可以用字符\,用来把两行或更多行的代码连接称一行(在 C 标准中这一过程称为“拼接(splicing)”)例如:

1
2
printf("When you conme to a fork in the road, take it. \
--Yogi Berra");

但是使用 \ 会有一个缺陷,就是下一行必须要顶格写,这样可能会破坏程序的缩进结构。可以使用下面真个更好的方法:

1
2
printf("When you come to a fork in the road, take it."
"--Yogi Berra");

字符串字面量的存储

C 语言中,把字符串字面量作为字符数组来处理,编译器在程序中遇到长度为 n 的字符串字面量时,回吧字符串字面量分配到长度为 n+1 的内存空间,这块内存空间将用来存储字符串字面量中的字符,以及一个标志字符串末尾的额外字符(空字符)。空字符是一个所有位都为 0 的字节,因此用转义序列 \0 来表示。

空字符 (‘\0’ )与 零字符(‘0’),空字符的码值为 0,零字符的码值为(ASCII 中为48)

1
printf("abc");

当调用 printf 函数时,会传递“abc” 的地址(即指向存储字母 a 的内存单元的指针)

字符串字面量的操作

1
2
3
char *p;

p = "abc"

C语言还允许对指针取下标:因此可以对字符串字面量取下标:

1
2
3
char ch;

ch = "abc"[1];

ch 的新值将是字母 b,

应用:把0~15的数转换成等价的十六进制的字符串形式:

1
2
3
char digit_to_hex_char(int digit){
return "123456789ABCDEF"[digit];
}

程序:

1
2
3
4
5
6
7
8
#include <stdio.h>
int main(){
int digit;
scanf("%d", &digit);
printf("%c\n","123456789ABCDEF"[digit]);

return 0;
}

字符串数组与字符指针

1
2
char date[] = "June 14";
char *date = "June 14";
  • 声明为数组时,就像任意数组元素一样,可以修改存储在 date 中的字符。
  • 声明为指针时,date 指向字符串字面量,字符串字面量是不可以被修改的

字符串的读和写

用 printf 函数和 puts 函数写字符串

1
2
3
4
5
6
7
8
#include <stdio.h>
int main(){
char word1[] = "are you having fun yet?";
printf("%s##\n", word1);
printf("%4.3s##\n", word1);

return 0;
}
1
2
are you having fun yet?
are##

printf(“%m.p%s”, s);

m 和 p 组合使用:转换说明%m.ps 会使字符串的前 p 个字符在大小为 m 的字段内显示。

m 表示至少输出 m 个字符,如果不够则默认右对齐,使用”-“可以强制左对齐。

puts 函数

使用方法:puts(str)

puts 函数只有一个参数,写完字符串后,puts 函数总会添加一个额外的换行符。

scanf 函数和 gets 函数读字符串

scanf 函数读入字符串永远不会包含空白字符

换行符、空格符、制表符空白字符都会使得 scanf 函数停止读入

gets 函数把读入地字符放到数组中,然后存储在一个空字符。

  • gets 函数不会再开始读字符串之前跳过空白字符
  • gets 函数会持续读入直到找到换行符才停止。gets 函数会忽略掉换行符,不会把它存储到数组中。

字符串函数

strlen

  • size_t strlen(const char *s)
  • 返回 s 的字符串的长度(不包括结尾的0)
1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
#include <string.h>

int main(int argc, char const *argv[]){
char line[] = "Hello";
printf("strlen = %lu\n", strlen(line));
printf("strlen = %lu\n", sizeof(line));

return 0;
}

输出:

1
2
strlen=5
sizeof=6

因为还有一个’\0’,所以 sizeof 的输出值为6


strcmp

  • int strcmp(const char s1, const char s2)

  • 比较两个字符串,返回:

    • 如果返回值 < 0,则表示 str1 小于 str2。
    • 如果返回值 > 0,则表示 str2 小于 str1。
    • 如果返回值 = 0,则表示 str1 等于 str2。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
#include <string.h>

int main ()
{
char str1[15];
char str2[15];
int ret;


strcpy(str1, "abcdef");
strcpy(str2, "ABCDEF");

ret = strcmp(str1, str2);

if(ret < 0)
{
printf("str1 小于 str2");
}
else if(ret > 0)
{
printf("str2 小于 str1");
}
else
{
printf("str1 等于 str2");
}

return 0;
}

输出:

1
str2 小于 str1

strcpy

  • char strcpy(char restrict dst, const char *restrict src);
  • 把 src 的字符串拷贝到 dst 中
    • restrict 表明 src 和 dst 不重叠(C99)
  • 返回 dst
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
#include <string.h>

int main()
{
char src[40];
char dest[100];

memset(dest, '\0', sizeof(dest));
strcpy(src, "lipsky.info");
strcpy(dest, src);

printf("最终的目标字符串: %s\n", dest);

return(0);
}

输出:

1
最终目标字符串:lipsky.info

strcat

  • char strcat(char restrict s1, const char *restrict s2);
  • 把 s2拷贝到s1的后面,接成一个长的字符串
  • 返回 s1
  • s1必须具有足够的空间
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
#include <string.h>

int main ()
{
char src[50], dest[50];

strcpy(src, "This is source");
strcpy(dest, "This is destination");

strcat(dest, src);

printf("最终的目标字符串: |%s|", dest);

return(0);
}

输出:

1
最终的目标字符串: |This is destinationThis is source|

注意:

strcpy 和 strcat 都是不安全的函数,存在数组越界的问题

安全的使用版本:

  • char strncpy(char restrict dst, const char *restrict src, size_t n);
  • char strncat(char restrict s1, const char *restrict s2, size_t n);
  • int strncmp(const char s1, const char s2, size_t n);

即多了一个参数 n ,这个参数用来判断,需要从源头复制到目标地址多少个字符

CATALOG
  1. 1. 字符串
    1. 1.0.1. 字符串常量
    2. 1.0.2. 字符串是选择用指针,还是用数组?
    3. 1.0.3. 字符串字面量
      1. 1.0.3.1. 延续字符串字面量
      2. 1.0.3.2. 字符串字面量的存储
      3. 1.0.3.3. 字符串字面量的操作
      4. 1.0.3.4. 字符串数组与字符指针
    4. 1.0.4. 字符串的读和写
      1. 1.0.4.1. 用 printf 函数和 puts 函数写字符串
      2. 1.0.4.2. scanf 函数和 gets 函数读字符串
    5. 1.0.5. 字符串函数
      1. 1.0.5.1. strlen
      2. 1.0.5.2. strcmp
      3. 1.0.5.3. strcpy
      4. 1.0.5.4. strcat
      5. 1.0.5.5. 注意: