(1)基本for循环写法,下标访问1
for(int i=0;'\0'!=s[i];++i){
printf("%c ",s[i]);
}
printf("\n");
(2)把下标访问改成指针访问,下标访问2
for(int i=0;'\0'!=*(s+i);++i){
printf("%c ",*(s+i));
}
printf("\n");
(3.1)for循环:使用指针操作,指针自己加,类似于数据结构里面的;
char* p = s;
for(;'\0'!=*p;++p){
printf("%c ",*p);
}
printf("\n");
(3.2)把for循环改成while
char* q = s;
while('\0'!=*q){
printf("%c ",*q);
++q;
}
printf("\n");
(4)使用后缀++,先打印,后自增(特殊);合并解引用和数组指针++操作
char* k = s;
while(*k){
printf("%c ",*k++);
}
printf("\n");
}
完整代码见001_string.c
#include
int main(){
char s[20];
scanf("%s",s);
// (1)基本for循环写法,下标访问1
for(int i=0;'\0'!=s[i];++i){
printf("%c ",s[i]);
}
printf("\n");
// (2)把下标访问改成指针访问,下标访问2
for(int i=0;'\0'!=*(s+i);++i){
printf("%c ",*(s+i));
}
printf("\n");
// (3.1)使用指针操作,指针自己加,类似于数据结构里面的;
char* p = s;
for(;'\0'!=*p;++p){
printf("%c ",*p);
}
printf("\n");
// (3.2)把for循环改成while
char* q = s;
while('\0'!=*q){
printf("%c ",*q);
++q;
}
printf("\n");
// (4)使用后缀++,先打印,后自增(特殊);合并解引用和数组指针++操作
char* k = s;
while(*k){
printf("%c ",*k++);
}
printf("\n");
}
(1.1)赋值法1:字符串
char s1[] = "Hello World";// (1.1)赋值法1:字符串数组
(1.2)赋值法2:字符串指针
char* s2 = "Hello World"; // (1.2)赋值法2:字符串指针
2.大小
(2.1)字符串数组:字符的个数;
printf("%p s1=%s\t sizeof(s1)=%d\n",s1,s1,sizeof(s1));//(2.1)字符串数组:字符的个数;
(2.2)字符串指针:指针字节数是计算机的长度;
printf("%p s2=%s\t sizeof(s2)=%d\n",s2,s2,sizeof(s2));//(2.2)字符串指针:指针字节数是计算机的长度;
- 是否可修改
s1[0] = 'p';
printf("s1=%s\n",s1);
3.1 字符串指针的指向字符变量,不可修改。
s2[6] = 'p';
s2[0] = 'p';
4.赋值
4.1 字符数组可以给字符串指针(变量)赋值
printf("%p s2=%s\n",s2,s2);
s2 = s1;
printf("%p s2=%s\n",s2,s2);
4.2字符数组名只是一个地址值,不能被赋值(错误)
s1 = s2;
3.2 .修改
// 字符串指针强制转化(①赋值②强制转化)指向字符数组,可以修改。
s2[6]='p';
printf("%p s2=%s\n",s2,s2);
printf("%p s1=%s\n",s1,s1);
}
完整代码见002_string.c
#include
int main(){
char s1[] = "Hello World";// (1.1)赋值法1:字符串
char* s2 = "Hello World"; // (1.2)赋值法2:字符串指针
// 1.大小
printf("%p s1=%s\t sizeof(s1)=%d\n",s1,s1,sizeof(s1));//(2.1)字符的个数;
printf("%p s2=%s\t sizeof(s2)=%d\n",s2,s2,sizeof(s2));//(2.2)指针字节数是计算机的长度;
// 2.是否可修改
s1[0] = 'p';
printf("s1=%s\n",s1);
// 2.1 字符串指针的指向字符变量,不可修改。
//s2[6] = 'p';
//s2[0] = 'p';
// 3.赋值
// 3.1 字符数组可以给字符串指针(变量)赋值
printf("%p s2=%s\n",s2,s2);
s2 = s1;
printf("%p s2=%s\n",s2,s2);
// 3.2字符数组名只是一个地址值,不能被赋值
//s1 = s2;
// 4.修改
// 字符串指针强制转化(①赋值②强制转化)指向字符数组,可以修改。
s2[6]='p';
printf("%p s2=%s\n",s2,s2);
printf("%p s1=%s\n",s1,s1);
}
scanf()
读入一个单词直到空白符(空格、回车、Tab)
scanf()
不安全,因为不知道要读入的内容长度,容易溢出。
例如:输入123456789
解决方式:指定读取的长度。
%
与s
之间的数字表示最多允许输入的字符数,这个数字要比数组长度少1
,打印的时候仅仅显示字符串长度的数据。
完整代码见003_sizeof.c
#include
int main(){
char str[8];
scanf("%7s",str);
printf("%s\n",str);
}
sscanf()
将字符串数组拆分为多个类型的变量,即拆分容器
char* date = "2019" "12" "21";
int year;
int month;
int day;
sscanf(date,"%4d%2d%2d",&year,&month,&day);//(1)拆分容器
printf("Y:%d\nM:%d\nD:%d\n",year,month,day);//(1.1)打印;
sprintf()
将多个类型的变量组合成字符串数组,即组合容器
char str[18];
sprintf(str,"%d年"
"%d月"
"%d日",year,month,day);//打印组合容器
(完整代码见004_string3.c)
#include
#include
int main(){
char* date = "2019" "12" "21";
int year;
int month;
int day;
sscanf(date,"%4d%2d%2d",&year,&month,&day);//(1)拆分容器
printf("Y:%d\nM:%d\nD:%d\n",year,month,day);//(1.1)打印;
// YYYY年MM月DD日 8+3*3+1
char str[18];
sprintf(str,"%d年"
"%d月"
"%d日",year,month,day);//打印组合容器
}
字符串传参方式与数组传参方式一样,只不过很多时候不需要传递字符串的长度(为什么?)。
void print_string(char str[]){
printf(str);
}
或者
void print_string(char* str){
printf(str);
}
字符串返回只能使用指针char*
交换
实现字符串交换函数void swap(char* s1,char* s2)
拼接
实现字符串拼接函数char* strcat(char* s1,char* s2)
拷贝
实现字符串拷贝函数char* strcpy(char* s1,char* s2)
比较
实现字符串相等判断函数bool strcmp(char* s1,char* s2)
1.交换函数,传入的是指针;
(1.1)保证有足够的长度,存下字符串;
(1.2)字符串的交换;
void swap(char* a,char* b){
printf("In Swap a=%s\tb=%s\n",a,b);
//char t = *a; // *(a+0) a[0]
//*a = *b;
//*b = t;
int len = strlen(a)>strlen(b)?strlen(a):strlen(b);//(1.1)保证有足够的长度,存下字符串;
for(int i=0;i<len+1;++i){
//(1.2)字符串的交换;
char t = a[i];
a[i] = b[i];
b[i] = t;
}
printf("In Swap a=%s\tb=%s\n",a,b);
}
2.字符串拼接
(2.1)返回结果字符串有利于链式操作
(2.2)进行拼接;
(2.3)尾部添加;
void Strcat(char* a,char* b){
int i;
for(i=0;'\0'!=a[i];++i);//(2.1)返回结果字符串有利于链式操作
int j;
for(j=0;'\0'!=b[j];++j,++i){
//(2.2)进行拼接;
a[i] = b[j];
}
a[i]='\0'; //(2.3)尾部添加;
//return a;
}
3.字符串复制函数:指针法(用字符指针做形参,以指针法访问元素),拷贝并替换;
void Strcpy(char *s1, char *s2)
{
while(*s1++ = *s2++);
}
4.字符串比较函数:返回两个字符串的差距;
int Strcmp(char *s1, char *s2)
{
while(*s1 == *s2)
{
if(*s1 == 0)
return 0;
s1++;
s2++;
}
return (*s1 - *s2);
}
完整代码见005_string_func.c
#include
#include
// 函数改变外部传入变量
// 1.传入指针
// 2.解引用
//1.交换函数,传入的是指针;
void swap(char* a,char* b){
printf("In Swap a=%s\tb=%s\n",a,b);
//char t = *a; // *(a+0) a[0]
//*a = *b;
//*b = t;
int len = strlen(a)>strlen(b)?strlen(a):strlen(b);//(1.1)保证有足够的长度,存下字符串;
for(int i=0;i<len+1;++i){
//(1.2)字符串的交换;
char t = a[i];
a[i] = b[i];
b[i] = t;
}
printf("In Swap a=%s\tb=%s\n",a,b);
}
//2.字符串拼接
void Strcat(char* a,char* b){
int i;
for(i=0;'\0'!=a[i];++i);//(2.1)返回结果字符串有利于链式操作
int j;
for(j=0;'\0'!=b[j];++j,++i){
//(2.2)进行拼接;
a[i] = b[j];
}
a[i]='\0'; //(2.3)尾部添加;
//return a;
}
//3.字符串复制函数:指针法(用字符指针做形参,以指针法访问元素),拷贝并替换;
void Strcpy(char *s1, char *s2)
{
while(*s1++ = *s2++);
}
//4.字符串比较函数:返回两个字符串的差距;
int Strcmp(char *s1, char *s2)
{
while(*s1 == *s2)
{
if(*s1 == 0)
return 0;
s1++;
s2++;
}
return (*s1 - *s2);
}
int main(){
char a[50],b[50];
scanf("%49s%49s",a,b);
printf("a=%s\tb=%s\n",a,b);
//swap(a,b);
//Strcat(a,b);
printf("%d\n",Strcmp(a,b));
//Strcpy(a,b);
printf("a=%s\tb=%s\n",a,b);
//printf("a=%s\tb=%s\n",Strcat(Strcat(a,b),b),b);
}
sizeof
与strlen()
(1)strlen()表示实际的字符串的长度,和数组,指针无关;
(2)sizeof()表示所有的长度,包括尾部;尤其是指针,表示计算机字长;
完整代码 见 006_sizeof_strlen.c
#include
#include
int main(){
char arr[] = "Hello World";
char* ptr = "Hello World";
//(1)strlen()表示实际的字符串的长度,和数组,指针无关;
//(2)sizeof()表示所有的长度,包括尾部;尤其是指针,表示计算机字长;
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));//
}
}
试一下下面三个例子
完整代码见00701——replace.c >>可以执行
#include
#include
int main(){
char arr[] = "Hello World";
arr[0] = 'h';
arr[6] = 'w';
printf("%s\n",arr);
}
完整代码见00702——replace.c(不允许修改,报错)
#include
#include
int main(){
char* ptr = "Hello World";;
*ptr = 'h';
*(ptr+6) = 'w';
printf("%s\n",ptr);
}
完整代码见00703——replace.c(允许修改)
#include
#include
int main(){
char arr[] = "Hello World";
char* ptr = arr;
*ptr = 'h';
*(ptr+6) = 'w';
printf("%s\n",ptr);
}
const
字符数组完整代码见00704_replace.c
不允许修改,报错;
#include
#include
int main(){
const char arr[] = "Hello World";
arr[0] = 'h';
arr[6] = 'w';
printf("%s\n",arr);
}
const
字符数组的字符串指针完整代码见00705_replace.c
特殊的。指向const字符数组的字符串指针,可以进行修改;(双重否定表示肯定)
#include
#include
int main(){
const char arr[] = "Hello World";
char* ptr = arr;
*ptr = 'h';
*(ptr+6) = 'w';
printf("%s\n",ptr);
}
决定能否修改的是指针指向的值能否修改。
const
的限制只针对定义为const
的变量。
字符串字面量初始化字符数组
字符串字面量初始化字符串指针
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
是一个字符数组,初始化把字符串字面量自动复制到数组中。
如何选择?
size_t strlen(const char *s);
返回字符串长度不包含\0
。
int strcmp(const char *s1,const char *s2);
比较两个字符串
返回0
,表示s1 == s2
返回>0
,表示s1 > s2
返回<0
,表示s1 < s2
为什么字符串不能直接比较?
为什么字符串比较会有大小?
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);
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空间不足,出现越界。
char* strchr(const char*s,int c);
char* strrchr(const char*s,int c);
返回找到字符的指针,没找到返回NULL
如何查找第二个?
char* strstr(const char*s1,const char*s2);
char* strcasestr(const char*s1,const char*s2);
学会通过例子,学会函数的使用。
复制
连接
比较
查找
其他
练习
实现函数times(char* dst,int n,char* src)
已知十天干和十二地支
天干:甲、乙、丙、丁、戊、己、庚、辛、壬、癸
地支:子、丑、寅、卯、辰、巳、午、未、申、酉、戌、亥
按顺序打印出六十甲子
甲子、乙丑、丙寅、丁卯、戊辰、己巳、庚午、辛未、壬申、癸酉、
甲戌、乙亥、丙子、丁丑、戊寅、己卯、庚辰、辛巳、壬午、癸未、
甲申、乙酉、丙戌、丁亥、戊子、己丑、庚寅、辛卯、壬辰、癸巳、
甲午、乙未、丙申、丁酉、戊戌、己亥、庚子、辛丑、壬寅、癸卯、
甲辰、乙巳、丙午、丁未、戊申、己酉、庚戌、辛亥、壬子、癸丑、
甲寅、乙卯、丙辰、丁巳、戊午、己未、庚申、辛酉、壬戌、癸亥
已知今年的纪年,输入21世纪任意年份,打印出对应的甲子。
已知今年的纪年,打印出21世纪所有年份的甲子。
已知小明同学的属相,推断出可能的年龄。
char*
一定是字符串吗?
char*
不一定是字符串,只有以0结尾的字符数组才是字符串。
0
、'\0'
与'0'
0
与'\0'
'\0'
表示字符串的结束,但不是字符串的一部分。计算字符串长度时不包含'\0'
。
字符串以数组方式存储,可以用数组或者指针形式访问。
char str[10]="";
这是一个空字符串,str[0]
为\0
。
char str[]="";
这是也是一个空字符串,str
数组长度为1
。
常见错误:使用未初始化的char*
char* str;
printf("%s\n",str);
同常如果指针定义时无法确定初始值时,使用NULL
初始化指针。
两个相邻字符串常量会自动连接。
char greeting = "Hello" "World";