1. 字符串操作
1.1 字符串遍历
可以通过数组方式遍历字符串。
char* str="Hello World";
for(int i = 0;'\0' != str[i];++i){
printf("%c\n",str[i]);
}
也可以使用指针方式
char* str="Hello World";
for(int i = 0;'\0' != *str;++i){
printf("%c\n",*(str+i));
}
指针方式可以简化成
char* str="Hello World";
for(;'\0' != *str;++str){
printf("%c\n",*str);
}
甚至是
while('\0' != *str){
printf("%c\n",*str++);
}
1.2 字符串赋值
char* s = "Hello World";
char* t;
t = s;
printf("%s\n",t);
没有产生新的字符串,只是s
和t
指向相同的字符串。下面是查看两个字符串的地址。
printf("%p\n",s);
printf("%p\n",t);
1.3 字符串输入输出
char str[8];
scanf("%s",str);
printf("%s\n",str);
scanf()
读入一个单词直到空白符(空格、回车、Tab)
scanf()
不安全,因为不知道要读入的内容长度,容易溢出。
例如:输入123456789
解决方式:指定读取的长度。
char str[8];
scanf("%7s",str);
printf("%s\n",str);
%
与s
之间的数字表示最多允许输入的字符数,这个数字要比数组长度少1
。
2. 字符串与函数
2.1 字符串传参
字符串传参方式与数组传参方式一样,只不过很多时候不需要传递字符串的长度(为什么?)。
void print_string(char str[]){
printf(str);
}
或者
void print_string(char* str){
printf(str);
}
2.2 字符串返回
字符串返回只能使用指针char*
3. 练习
- 交换
实现字符串交换函数void swap(char* s1,char* s2)
- 拼接
实现字符串拼接函数char* strcat(char* s1,char* s2)
- 拷贝
实现字符串拷贝函数char* strcpy(char* s1,char* s2)
- 比较
实现字符串相等判断函数bool strcmp(char* s1,char* s2)
4. 字符串指针与字符数组的区别
4.1 sizeof
与strlen()
#include <stdio.h>
#include <string.h>
int main(){
char arr[] = "Hello World";
char* ptr = "Hello World";
printf("sizeof(arr) = %ld\n",sizeof(arr));
printf("strlen(arr) = %ld\n",strlen(arr));
printf("sizeof(ptr) = %ld\n",sizeof(ptr));
printf("strlen(ptr) = %ld\n",strlen(ptr));
}
4.2 替换字符
试一下下面三个例子
- 修改字符数组
#include <stdio.h>
#include <string.h>
int main(){
char arr[] = "Hello World";
arr[0] = `h`;
arr[6] = `w`;
printf("%s\n",arr);
}
- 字符串指针
#include <stdio.h>
#include <string.h>
int main(){
char* ptr = "Hello World";;
*ptr = `h`;
*(ptr+6) = `w`;
printf("%s\n",ptr);
}
- 指向字符数组的字符串指针
#include <stdio.h>
#include <string.h>
int main(){
char arr[] = "Hello World";
char* ptr = arr;
*ptr = `h`;
*(ptr+6) = `w`;
printf("%s\n",ptr);
}
-
const
字符数组
#include <stdio.h>
#include <string.h>
int main(){
const char arr[] = "Hello World";
arr[0] = 'h';
arr[6] = 'w';
printf("%s\n",arr);
}
- 指向
const
字符数组的字符串指针
#include <stdio.h>
#include <string.h>
int main(){
const char arr[] = "Hello World";
char* ptr = arr;
*ptr = 'h';
*(ptr+6) = 'w';
printf("%s\n",ptr);
}
决定能否修改的是指针指向的值能否修改。
const
的限制只针对定义为const
的变量。
4.3 字符串字面量初始化
字符串字面量初始化字符数组
字符串字面量初始化字符串指针
char* str1 = "Hello World";
char str2[] = "Hello World";
str1[5] = '\0'; // Error
str2[5] = '\0'; // OK
printf("str1=%s\n",str1);
printf("str2=%s\n",str2);
str1
是一个指针,初始化指向一个字符串常量。(在C99标准中,str1
报警告,提示应该使用const char*
)
修改字符串常量可能会导致严重后果。
str2
是一个字符数组,初始化把字符串字面量自动复制到数组中。
如何选择?
- 如果需要构造字符串使用数组;如果需要处理字符串使用指针。
- 字符串不需要修改使用字符串字面量初始化字符串指针。
- 字符串需要修改使用字符串字面量初始化字符数组。
5. 字符串函数
5.1 字符串长度
size_t strlen(const char *s);
返回字符串长度不包含\0
。
5.2 字符串比较
int strcmp(const char *s1,const char *s2);
比较两个字符串
返回0
,表示s1 == s2
返回>0
,表示s1 > s2
返回<0
,表示s1 < s2
为什么字符串不能直接比较?
为什么字符串比较会有大小?
5.3 字符串拷贝
char* strcpy(char* restrict dst,const char* restrict src);
把字符换src拷贝到dst。
restrict
是C99关键字,表示src和dst不能重叠,便于并行处理。
返回值为dst,便于连接。
连续赋值。
复制一个字符串
// char* dst = (char*)malloc(strlen(src)+1);
char dst[strlen(src)+1];
strcpy(dst,src);
5.4 字符串连接
char* strcat(char* restrict s1,const char*restrict s2);
把s2拷贝到s1的后面,拼接成一个长的字符串。
返回s1,注意:s1必须有足够的空间。
char* a="Hello";
char* b="World";
char res[strlen(a)+strlen(b)+1] = {0};
strcat(strcat(res,a),b);
strcpy和strcat都会有安全问题:dst空间不足,出现越界。
5.5 字符查找
char* strchr(const char*s,int c);
char* strrchr(const char*s,int c);
返回找到字符的指针,没找到返回NULL
如何查找第二个?
5.6 子串查找
char* strstr(const char*s1,const char*s2);
char* strcasestr(const char*s1,const char*s2);
6. 文档
学会通过例子,学会函数的使用。
stdio.h
stdlib.h
string.h
复制
连接
比较
查找
其他
练习
实现函数times(char* dst,int n,char* src)
7. 字符串数组与字符串指针数组
7.1 字符串数组
字符串数组,可以看成二维字符数组,只是初始化可以使用字符串方式。
char arr[12][10] = {"January","February","March","April",
"May","June","July","August",
"September","October","November","December"};
简化
char arr[][10] = {"January","February","March","April",
"May","June","July","August",
"September","October","November","December"};
7.2 字符串指针数组
char* arr[12] = {"January","February","March","April",
"May","June","July","August",
"September","October","November","December"};
简化
char* arr[] = {"January","February","March","April",
"May","June","July","August",
"September","October","November","December"};
7.3 字符串数组与字符串指针数组的区别
- 大小的区别
char arr1[][10] = {"January","February","March","April",
"May","June","July","August",
"September","October","November","December"};
char* arr2[] = {"January","February","March","April",
"May","June","July","August",
"September","October","November","December"};
printf("sizeof(arr1)=%d\n",sizeof(arr1));
printf("sizeof(arr2)=%d\n",sizeof(arr2));
- 二维指针的区别
#include <stdio.h>
int main () {
char arr1[][10] = {"January","February","March","April",
"May","June","July","August",
"September","October","November","December"};
char* arr2[] = {"January","February","March","April",
"May","June","July","August",
"September","October","November","December"};
char** p1 = arr1;
for(int i=0;i<12;++i){
printf("%s\n",p1[i]);
}
char** p2 = arr2;
for(int i=0;i<12;++i){
printf("%s\n",p2[i]);
}
return 0;
}
8. 实践
已知十天干和十二地支
天干:甲、乙、丙、丁、戊、己、庚、辛、壬、癸
地支:子、丑、寅、卯、辰、巳、午、未、申、酉、戌、亥
按顺序打印出六十甲子
甲子、乙丑、丙寅、丁卯、戊辰、己巳、庚午、辛未、壬申、癸酉、
甲戌、乙亥、丙子、丁丑、戊寅、己卯、庚辰、辛巳、壬午、癸未、
甲申、乙酉、丙戌、丁亥、戊子、己丑、庚寅、辛卯、壬辰、癸巳、
甲午、乙未、丙申、丁酉、戊戌、己亥、庚子、辛丑、壬寅、癸卯、
甲辰、乙巳、丙午、丁未、戊申、己酉、庚戌、辛亥、壬子、癸丑、
甲寅、乙卯、丙辰、丁巳、戊午、己未、庚申、辛酉、壬戌、癸亥已知今年的纪年,输入21世纪任意年份,打印出对应的甲子。
已知今年的纪年,打印出21世纪所有年份的甲子。
已知小明同学的属相,推断出可能的年龄。
9. main()
参数与返回值
9.1 main()
参数
main()
的完全形式是这样的。
int main(int argc,char* argv[])
或者
int main(int argc,char** argv)
其中,argc
是命令与参数数量。argv
是命令和参数组成的字符串数组。argv[0]
是命令本身。其余是参数。
int main(int argc,char* argv[]){
for(int i=0;i<argc;++i){
printf("%d:%s",i,argv[i]);
}
return 0;
}
9.2 main()
返回值
main()
返回值是与调用程序交互的,返回程序执行状态。通常0
表示执行成功,非零表示执行失败。
int main(){
int n;
printf("请输入一个整数:");
scanf("%d",&n);
return n;
}
在终端执行程序后,接着执行echo $?
可以看到返回值。
10. 扩展
char*
一定是字符串吗?
char*
不一定是字符串,只有以0结尾的字符数组才是字符串。
10.1 0
、'\0'
与'0'
0
与'\0'
'\0'
表示字符串的结束,但不是字符串的一部分。计算字符串长度时不包含'\0'
。
字符串以数组方式存储,可以用数组或者指针形式访问。
10.2 空字符串
char str[10]="";
这是一个空字符串,str[0]
为\0
。
char str[]="";
这是也是一个空字符串,str
数组长度为1
。
常见错误:使用未初始化的char*
char* str;
printf("%s\n",str);
同常如果指针定义时无法确定初始值时,使用NULL
初始化指针。
10.3 字符串常量连接
两个相邻字符串常量会自动连接。
char greeting = "Hello" "World";
小礼
作者:jdzhangxin
链接:https://www.jianshu.com/p/0eb5ad941416
侵删。