Lipsky

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. 注意:#