ThankNeko's Blog ThankNeko's Blog
首页
  • 操作系统

    • Linux基础
    • Linux服务
    • WindowsServer笔记
    • Ansible笔记
    • Shell笔记
  • 容器服务

    • Docker笔记
    • Kubernetes笔记
    • Git笔记
  • 数据库服务

    • MySQL笔记
    • ELK笔记
    • Redis笔记
  • 监控服务

    • Zabbix笔记
  • Web服务

    • Nginx笔记
    • Tomcat笔记
  • 数据处理

    • Kettle笔记
  • Python笔记
  • Bootstrap笔记
  • C笔记
  • C++笔记
  • Arduino笔记
  • 分类
  • 标签
  • 归档
  • 随笔
  • 关于
GitHub (opens new window)

Hoshinozora

尽人事,听天命。
首页
  • 操作系统

    • Linux基础
    • Linux服务
    • WindowsServer笔记
    • Ansible笔记
    • Shell笔记
  • 容器服务

    • Docker笔记
    • Kubernetes笔记
    • Git笔记
  • 数据库服务

    • MySQL笔记
    • ELK笔记
    • Redis笔记
  • 监控服务

    • Zabbix笔记
  • Web服务

    • Nginx笔记
    • Tomcat笔记
  • 数据处理

    • Kettle笔记
  • Python笔记
  • Bootstrap笔记
  • C笔记
  • C++笔记
  • Arduino笔记
  • 分类
  • 标签
  • 归档
  • 随笔
  • 关于
GitHub (opens new window)
  • Python笔记

  • C笔记

    • C介绍与数据类型
    • C运算与表达式
    • C数组与指针
    • C字符串与常用函数
      • 字符串
        • 介绍
        • 字符串声明
        • printf函数
        • scanf函数
        • 转义符号
        • 不同类型输出格式符号
        • 使用字符类型
        • 字符串浅拷贝
        • 字符串深拷贝
        • 常用函数
  • C++笔记

  • Arduino笔记

  • Dev
  • C笔记
Hoshinozora
2024-05-02
目录

C字符串与常用函数

# 字符串

# 介绍

字符串(character string)是一个或多个字符的序列,例如:"hello,world!",C语言没有专门用于存储字符串的变量类型,字符串都被存储在char类型的数组中,每个单元存储一个字符。 字符串的末尾还会自动添加一个空字符'\0'作为结束标识,这意味着数组大小至少要比待存储字符串中的字符数多1。

  • 定义字符串:char text[14] = "Hello, world!";
  • 输入字符串:scanf("%s", 字符串变量); 由于数组变量的值是数组本身的指针,所以直接指定字符串变量名即可。

# 字符串声明

// 声明字符串
char msg1[] = "It's My GO!!!!!";
// 指针方式声明字符串,该方式无法通过索引针对字符进行修改,所以一般会加上常量限定符
const char * msg3 = "It's My GO!!!!!";


// 声明字符串数组
char msg[2][10] = {"It's", "MyGO!!!!!"};

// 指针方式声明字符串数组,可以针对元素进行修改,但无法针对字符进行修改,所以一般会加上常量限定符
const char * msg2[] = { "It's", "MyGO!!!!!" };
1
2
3
4
5
6
7
8
9
10
11

数组声明和指针声明的区别:

  1. 数组声明可以通过arr[n]='x';修改字符值,而指针声明不行,但指针声明也可以通过[]进行读取arr[n]。
  2. 指针声明可以通过*(arr++)进行递增操作,而数组声明不行,但数组声明也可以进行加法*(arr + n)。

# printf函数

printf(格式字符串, 格式值1, 格式值2...);,格式化输出字符串,会将字符串中的格式字符按顺序替换传入的格式值参数。

例如:printf("my age is: %d\n", 18);

# scanf函数

scanf("格式化字符串", 指针1,...);,阻塞程序并接收输入的内容,直到回车。scanf函数在读取值到基本类型变量时需要使用&,数组等非基本类型则不需要。scanf函数正常会返回读取的数量,如果没有读取任何项、或需要读取一个数字而用户却输入一个非数值字符串,scanf便返回0。

这是个不安全的函数,如果需要使用则要在源代码最顶部添加#define _CRT_SECURE_NO_WARNINGS来禁用警告即可。 scanf函数会使用空白(换行符、制表符和空格)把输入分成多个字段,我们可以指定多个变量来接收输入的多个字段。比较特殊的是%c,它会读取每个字符包括空格。 另外还需要注意在读取字符串时如果字符串用空格隔开,则会出现单个变量只读取到了第一段的情况,也就是说输入字符串hello world只会读取hello。所以一般我们会使用其他更常用的函数来读取字符串输入。

例如:

// 会将接收的输入内容进行格式化,并将第一段并作为值,传入到myAge变量中去。
int myAge;
scanf("%d", &myAge);

// 可以一次传入多个值到不同变量中,如果格式化字符串的参数使用任意空白字符隔开,则我们输入时也可以使用任意空白字符隔开,空白字符可以是单个空格、多个空格、或则直接不隔开,"%d %d" = "%d  %d" = "%d%d"。
int myPhone, myScore;
scanf("%d %d", &myPhone, &myScore);
// 如果格式化字符串的参数使用非空格字符隔开,则我们输入时需要严格按照格式进行输入,例如此处值之间必须一个,隔开。
scanf("%d,%d", &myPhone, &myScore);

// 传入字符串
char myName[40];
scanf("%s", myName);
1
2
3
4
5
6
7
8
9
10
11
12
13

其他用法:

  • scan函数可以限制输入的字符长度,在格式化字符串中添加限定的长度即可%[限定的长度]类型,例如:%20d
  • scan函数还可以跳过特定输入项,在格式化字符串时把*加入到要跳过的%和待转格式之间即可,例如:
int n;
// 此时如果输入1 2 3则会跳过1和2,只将3赋值给n变量
scanf("%*d %*d %d", &n);
1
2
3

# 转义符号

\a 警报(ANSI C) \b 退格 \f 换页 \n 换行 \r 回车 \t 水平制表符 \v 垂直制表符 \\ 反斜杠(\) \' 单引号 \" 双引号 \? 问号 \0oo 八进制值(oo必须是有效的八进制数,即每个o可表示0~7中的一个数) \xhh 十六进制值(hh必须是有效的十六进制数,即每个h可表示0~f中的一个数)

# 不同类型输出格式符号

  • 浮点类型:%.nf,其中%.nf表述输出小数点后n位,例如%.2f
  • 指数计数法打印浮点类型:%e、%E
  • P计数法打印浮点类型:%a、%A
  • 指数计数法打印long double类型:%Lf、&Le
  • int类型:%d
  • short类型:%hd
  • long类型:%ld
  • long long类型:%lld
  • unsigned int类型:%u
  • unsigned short类型:%hu
  • unsigned long类型:%lu
  • unsigned long long类型:%llu
  • 输出指针:%p
  • 输出指针差值:%td
  • 八进制输出int类型:%o,要加前缀0则使用%#o
  • 十六进制输出int类型:%x,要加前缀0x或0X则使用%#x、%#X
  • 八进制输出long类型:%lo
  • 十六进制输出long类型:%lx
  • 八进制输出short类型:%ho
  • 十六进制输出short类型:%hx
  • 输出字符串:%s
  • 输出百分号:%%
  • 格式输出字符串:%[指定0会补零,不指定补空格][对齐长度]类型
    • 对齐长度:如果为正数则是右对齐,负数则是左对齐,*表示由printf的参数决定而非字符串固定,例如:printf("%24d", num)、printf("%-24d", num)、printf("%*d", 24, num)、printf("%*.*f", 24, f_var, 2);

# 使用字符类型

字符类型用于存储单个字符串,在赋值时可以直接赋值单个字符、也可以指定字符代码,赋值字符时需要使用引号包裹。 例如:

// 会将字符转化为对应的字符代码进行存储
char ima = 'A';
// 直接指定字符代码,可读性不好,不建议使用
char ima_num = 65;
// 打印字符类型,输出结果为:A A 65
printf("%c %c %d", ima, ima_num, ima);
1
2
3
4
5
6

# 字符串浅拷贝

直接通过arr2 = arr1;方式进行的拷贝就是浅拷贝,浅拷贝会将arr1值的数组首指针地址,复制给arr2作为值,也就是两者指向同一个数组的首指针。

例如:

#include <stdio.h>

int main(void){
 const char * mesg = "Don't be a fool!";
 const char * copy;
 copy = mesg;
 printf("%s\n", copy);
 printf("mesg = %s; &mesg = %p; value = %p\n", mesg, &mesg,
mesg);
 printf("copy = %s; &copy = %p; value = %p\n", copy, &copy,
copy);
 return 0;
}

// 输出
>> Don't be a fool!
>> mesg = Don't be a fool!; &mesg = 0x0012ff48; value = 0x0040a000
>> copy = Don't be a fool!; &copy = 0x0012ff44; value = 0x0040a000
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 字符串深拷贝

# strcpy函数

深拷贝需要使用strcpy函数,可以把整个字符串从拷贝至目标数组。或者使用strncpy函数指定仅拷贝前n个字符数。

第1个参数需要指向一个数据对象,如数组。

第2个指针可以是指针、数组名或字符串常量。

这是个不安全的函数,如果需要使用则要在源代码最顶部添加#define _CRT_SECURE_NO_WARNINGS来禁用警告即可。或使用strcpy_s函数代替。

库:string.h

例如:

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

int main(void) {
    
    char mesg[10] = "hello";
    char copy[10];
    strcpy(copy, mesg);
    printf("%s\n", copy);
    printf("mesg = %s; &mesg = %p; value = %p\n", mesg, &mesg,
        mesg);
    printf("copy = %s; &copy = %p; value = %p\n", copy, &copy,
        copy);
    return 0;
}

// 输出,可以看到两者值存储到了不同的内存空间
>> hello
>> mesg = hello; &mesg = 0000001C57CFF8B8; value = 0000001C57CFF8B8
>> copy = hello; &copy = 0000001C57CFF8E8; value = 0000001C57CFF8E8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# strcpy_s函数

与strcpy不同的是,该函数可以指定目标字符串的最大长度,以防止缓冲区溢出。

库:string.h

函数:strcpy_s(目标字符串, 最大长度, 拷贝字符串);

# 常用函数

# getchar函数

getchar函数用于更简洁的方式接收标准输入的字符,包括空白字符。

库:stdio.h

函数:getchar() - 返回值是接收的字符。

例如:

char ch;
// 同等于scanf("%c", &ch);
ch = getchar();
printf("%c", ch);
1
2
3
4

# putchar函数

getchar函数用于更简洁的方式打印输出字符。

库:stdio.h

函数:putchar()

例如:

char ch = 'A';
// 同等于printf("%c", ch);
putchar(ch);
1
2
3

# puts函数

puts函数与printf函数类似,但只能用来输出字符串,且在输出时会在末尾自动加上换行符。

库:stdio.h

例如:

char oneMsg[] = "Who are they?"
char * twoMsg = "It's My GO!!!!!";
puts(oneMsg);
puts(twoMsg);
1
2
3
4

# gets函数

gets函数用于读取整行输入,直至遇到换行符,然后丢弃换行符存储其余字符。

更建议使用fgets函数而非gets函数。因为该函数无法确保字符串能够被数组装下,所以输入内容如果超过数组能够存储的长度,就会导致缓冲区溢出,是个不安全的函数。

gets是不安全的输入函数,所以一般使用fgets或gets_s函数作为代替。

库:stdio.h

例如:

char testArr[10];
gets(testArr);
puts(testArr);
1
2
3

# fgets函数

fgets函数用于从屏幕或文件读入字符串,该函数会通过限制字符数来解决溢出的问题。与gets不同fgets函数不会丢弃换行符。

fgets函数的第1个参数指明用于输入的字符串数组。

fgets函数的第2个参数指明了读入字符的最大数。如果该参数的值是n,那么fgets将读入n-1个字符,或者读到遇到的第一个换行符为止。

fgets函数的第3个参数指明要读入的文件。如果需要读入从键盘输入的数据,则需要以stdin作为参数。

fgets()函数正常会返回指向char的指针,与传入的第1个参数相同。但如果函数读到文件结

尾,它将返回一个特殊的指针:空指针。该指针保证不会指向有效的数据,所以可用于标识这种特殊情况。在代码中表示空指针可以使用数字0表示,但一般使用宏NULL表示更常见。

库:stdio.h

# fputs函数

fputs函数用于输出字符串到屏幕或文件。与puts不同fputs函数不会在末尾进行换行。

fputs函数的第1个参数指明它要输出的字符串数组。

fputs函数的第2个参数指明它要写入的文件。如果要输出到计算机屏幕上,则需要以stdout作为参数。

库:stdio.h

# gets_s函数

C11新增了gets_s函数,该函数与fgets函数类似,用一个参数限制读入的字符数。但gets_s函数只从标准输入中读取数据,所以不需要第3个参数。另外gets_s与gets函数一样会丢弃末尾的换行符。

如果gets_s读到最大字符数都没有读到换行符,则会把目标数组中的首字符设置为空字符,然后返回空指针。所以一般还是使用fgets更灵活。

库:stdio.h

# strlen函数

strlen函数用于获取字符串的实际长度。

库:string.h

函数:strlen(字符串变量) - 获取数组内字符串的长度,空字符不会算在内。

例如:

char name[10] = "hello";
// 返回5,表示实际字符为5个
printf("%d", strlen(name));
1
2
3

# strcat函数

strcat函数接受两个字符串作为参数,用于拼接字符串。该函数把第2个字符串的备份附加在第1个字符串末尾,并把拼接后的新字符串作为第1个字符串,并返回第1个字符串的地址。

strcat函数无法检查第1个数组是否能容纳第2个字符串,所以可能会出现缓冲区溢出的情况。

这是个不安全的函数,如果需要使用则要在源代码最顶部添加#define _CRT_SECURE_NO_WARNINGS来禁用警告即可。或使用strcat_s函数代替。

库:string.h

例如:

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


int main(void) {
    char content[10] = "abc";
    strcat(content, "defg");
    puts(content);
    return 0;
}


// 输出
>> abcdefg
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# strcat_s函数

与strcat不同的是,该函数可以指定目标字符串的最大长度,以防止缓冲区溢出。

库:string.h

函数:strcat_s(目标字符串, 最大长度, 拼接字符串);

例如:

#include <stdio.h>
#include <string.h>
#define SIZE 10

int main(void) {
    
    char content[SIZE] = "abc";
    strcat_s(content, SIZE, "defg");
    puts(content);
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11

# strncat函数

strncat函数与strcat不同的地方在于,strncat的第3个参数可以指定最大添加字符数。

这是个不安全的函数,如果需要使用则要在源代码最顶部添加#define _CRT_SECURE_NO_WARNINGS来禁用警告即可。或使用strncat_s函数代替。

库:string.h

例如:

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

int main(void) {
    char content[10] = "abc";
    strncat(content, "defg", 2);
    puts(content);
    return 0;
}


// 输出
>> abcde
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# strncat_s函数

与strncat不同的是,该函数可以指定目标字符串的最大长度,以防止缓冲区溢出。

库:string.h

函数:strncat_s(目标字符串, 最大长度, 拼接字符串, 拼接长度);

例如:

#include <stdio.h>
#include <string.h>
#define SIZE 10

int main(void) {
    
    char content[SIZE] = "abc";
    strncat_s(content, SIZE, "defg", 3);
    puts(content);
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11

# strcmp函数

strcmp函数用于比较的是字符串的内容。如果两个字符串参数的内容相同,该函数返回0,否则返回非零值。

库:string.h

例如:

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

int main(void) {
    
    char a[10] = "abc";
    char b[5] = "cde";
    char c[5] = "abc";
    printf("%d\n", strcmp(a, b)); // 返回-1
    printf("%d\n", strcmp(a, c)); // 返回0
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12

# strncmp函数

与strcmp不同的是strncmp函数可以指定仅对比前n位字符串。

库:string.h

例如:

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

int main(void) {
    
    char a[5] = "abc";
    char b[5] = "abe";
    printf("%d\n", strncmp(a, b, 2)); // 返回0
    return 0;
}

1
2
3
4
5
6
7
8
9
10
11

# 自定义输出函数

我们可以通过循环+指针来判断字符串是否输出完毕。

例如:

#include <stdio.h>

int put1(const char* string) {
    int count = 0;
    // 如果*string指向'\0'空字符则表示输出完毕,空字符会被作为条件假。
    while (*string) {
        putchar(*string++);
        count++;
    }
    return count;
}

int main(void) {
    printf("   %d", put1("tet"));
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 字符判断函数

C提供一系列函数来判断字符是否属于某特别的类别。属于则返回真,否则返回假。

库:ctype.h

函数:

// 判断字符是否为字母
isalpha()
// 判断字符是否为字母/数字
isalnum()
// 判断是否为标准空白字符(空格、水平制表符或换行符)或任何其他本地化指定为空白的字符
isblank()
// 判断是否为控制字符,如Ctrl+B
iscntrl()
// 判断是否为数字
isdigit()
// 判断是否为除空格之外的任意可打印字符
isgraph()
// 判断是否为小写字母
islower() 
// 判断是否为可打印字符
isprint()
// 判断是否为标点符号(除空格或字母数字字符以外的任何可打印字符)
ispunct()
// 判断是否为空白字符(空格、换行符、换页符、回车符、垂直制表符、水平制表符或其他本地化定义的字符)
isspace()
// 判断是否为大写字母
isupper()
// 判断是否为十六进制数字符
isxdigit()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 大小写转换函数

大小写转换函数用于将大写字符转化为小写、或将小写转化为大写。

库:ctype.h

函数:

// 如果参数是大写字符,该函数返回小写字符;否则,返回原始参数
tolower() 
// 如果参数是小写字符,该函数返回大写字符;否则,返回原始参数
toupper()
1
2
3
4

# 字符串转换函数

库:stdlib.h

// 将字符串转化为int整数并返回
atoi(字符串)

// 将字符串转化为double浮点数并返回
atof(字符串)

// 将字符串转化为long长整数并存储到指定对象
strtol(字符串, &变量名, 字符串中的进制数)
    
// 将字符串转化为unsigned long无符号长整数并存储到指定对象
strtoul(字符串, &变量名, 字符串中的进制数)

// 将字符串转化为double浮点数并存储到指定对象
strtod(字符串, &变量名, 字符串中的进制数)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#C语言#字符串
C数组与指针
C++基本介绍

← C数组与指针 C++基本介绍→

最近更新
01
二〇二五年四月十七日随笔
04-17
02
二〇二五年四月十六日随笔
04-16
03
二〇二五年四月九日随笔
04-09
更多文章>
Theme by Vdoing | Copyright © 2022-2025 Hoshinozora | MIT License
湘ICP备2022022820号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式