C语言:字符串

目录

字符串

字符串

字符串变量

字符串常量

是一个const

 指针还是数组?

char* 与字符串

字符串输入输出

字符串赋值

字符串输入输出

 常见错误

空字符串

字符串数组

两种表示的区别

指针表示

程序参数

单字符输入输出——putchar, getchar

putchar

getchar

与 printf 和 scanf 

 字符串函数——头文件 string.h

strlen —— lenth

返回 s 的字符串长度(不包括结尾的 ' \0 ' ) 

 自己实现 strlen 

strcmp —— compare

比较两个字符串

自己实现 strcmp 

strcpy —— copy

把 src 的字符串拷贝到 dst(包括 ' \0 ' )

复制一个字符串

自己实现strcpy

strcat —— catenate

 把 s2 拷贝到 s1 后面,接成一个长字符串

问题 

安全版本

字符串搜索函数

字符串中找字符

如何找第二个?

拷贝练习

输出找到的 l 之前的字符

字符串中找字符串

字符串

char word []={'H','e','l','l','o','\0'}
  • 一定要有 ‘\0’ 

字符串

  • 以 0(整数0)结尾的一串字符

             0 或 ‘\0’ 是一样的,但是和 ‘0’ 不同

  • 0标志字符串的结束,但不是这个字符串的一部分

              计算字符串长度的时候不包含这个0

  • 字符串以数组的形式存在,以数组或指针的形式访问

              更多是以指针形式 

  • < string.h > 里有很多处理字符串的函数 
  • C语言的字符串是以字符数组的形态存在的

              不能用运算符对字符串做运算

              通过数组的方式可以遍历字符串 

  • 字符串字面量可以用来初始化字符数组 

字符串变量

char *str = "Hello" ;
char word [] = "Hello" ;
char line [10] = "Hello" ;

字符串常量

  • “Hello”会被编译器变成一个字符数组放在某处,这个数组的长度是 6 ,结尾有表示结束的 0 . 
  • 两个相邻的字符串常量会被自动连接起来
printf("你好,"
        "你过得好吗");
// ---------> 你好,你过得好吗

printf("你好,\
你过得好吗");
// ---------> 你好,你过得好吗

printf("你好,\
        你过得好吗");
// ---------> 你好,         你过得好吗
  • 如果程序里有两处相同的东西,这两个指针会指向同一个地方: 
char* p1 = "Hello world" ;
char* p2 = "Hello world" ;
 
printf ( "%p",p ) ;
printf ( "%p",p1 ) ;

//两者结果相同

这两个地址指针指向同一个地址,且地址很小,位于程序的代码段, 只读  

是一个const

char* s = "Hello world" ;
  • s 是一个指针,初始化为一个字符串常量
  • s 实际上是 const char* s,只能读不能修改

 如果想修改字符串,应该用数组:

char s[] = "Hello world" ;

 指针还是数组?

  • 数组:构造了一个字符串,这个字符串就在这里,作为本地变量空间自动被回收
  • 指针:不知道字符串在哪,用于 (1) 处理函数参数 ; (2) 动态分配空间 ; (3)不需要重写

要构造一个字符串 --------> 数组

要处理一个字符串 ---------> 指针

char* 与字符串

  • 字符串可以表达为 char* 的形式
  • char* 不一定是字符串

本意是指向字符的指针,也可能是指向字符的数组的指针

只有它所指的字符数组结尾有 0 ,才能说它指向的是字符串

字符串输入输出

字符串赋值

char* i = "title" ;
char j ;
j = i ;

结果是让 j 也指向 i 所指向的内容

字符串输入输出

scanf 读入一个单词(到空格、tab或回车为止)

scanf 是不安全的,因为不知道要读入的内容的长度

#include <stdio.h>
int main()
{
	char word[8];
	scanf ("%s", word ) ;
	printf ("%s##\n", word ) ;
	return 0;
}
//输入 Hello world
//输出 Hello##
#include <stdio.h>
int main()
{
	char word[8];
	char word2[8];
	scanf ("%s", word ) ;
	scanf ("%s", word2 ) ;
	printf ("%s##%s##\n", word,word2 ) ;
	
	return 0;
}
//输入 Hello world
//输出 Hello##world##

 字符如果过长,超出了所定义 char [ i ] 的值,那么程序会出错,这种情况可以这样:

char word[8] ;
scanf ("%7s",word) ;

 scanf ("%7s",word) ;

(这个数字应该比数组的大小小1,因为字符串结尾有 '\0' )

表示最多读 7 个字符,不会出错但不一定完整

#include <stdio.h>
int main()
{
	char word[8];
	char word2[8];
	scanf ("%7s", word ) ;
	scanf ("%7s", word2 ) ;
	printf ("%s##%s##\n", word,word2 ) ;
	
	return 0;
}

  

如果第一次输入的字符数超出定义中的数,那么就是按照字符个数来读入,而不是空格

 常见错误

  • 以为 char* 是字符串类型,定义了一个字符串类型的变量 string 就可以直接使用

char *string 只是一个指针变量,未指向某块内存空间时不能直接用

  •    (由于没有对 string 初始化为 0 ,所以不一定每次运行都出错)

空字符串

char buffer [100] = "" ;
  • 这是一个空的字符串,buffer [ 0 ] == ' \0 '  
char buffer [] = "" ;
  • 这个数组的长度只有 1 ,buffer [ 0 ] == ' \0 '------> 放不下任何字符串 

字符串数组

两种表示的区别

char word[]="hello";

char word[]={'h','e','l','l','o','\0'};

如上,“ ” 型会自动在字符串后加 ‘\0’ ,而 { } 型需要自己加上

指针表示

char **a
  • a 是一个指针,指向另一个指针,那个指针指向一个字符(串)
char a[][]     //no

char a[][10]   //a[0] --> char [10]

程序参数

int main ( int argc, char const *argv[] )

argc 告诉后面的字符串数组一共有几个字符串 

argv [ 0 ] 是命令本身,当使用 Unix 的符号链接时,反映符号链接的名字 

单字符输入输出——putchar, getchar

putchar

int putchar ( int c ) ;
  • 向标准输出写一个字符
  • 返回类型是 int 
  • 返回写了几个字符,EOF(-1)表示写失败 

getchar

int getchar ( void ) ;
  • 从标准输入读入一个字符
  • 返回类型 int ,是为了返回 EOF (-1)
CTRL-C ---> 强制程序结束
CTRL-Z ---> 程序得到了EOF状态  (windows)
CTRL-D ---> 程序得到了EOF状态  (linux)

以下一个简单的代码 

#include<stdio.h>
int main(int argc,char const *argv[])
{
	int ch;
	
	while((ch=getchar())!=EOF){
		putchar(ch);
	}
	
	printf("EOF\n");
	return 0;
}

在按下回车之后,才会有字符输出 

  • 当输入CTRL-Z,shell 内出现 -1 表示 EOF
  • 当输入CTRL-C,shell 直接将程序关闭

getchar 是一个个读入1,2,3

scanf ( "%d" ,) 是将123作为整体的一个数读入

与 printf 和 scanf 

scanf和printf函数需要通过格式化字符串指定输入输出的格式,并使用特定的格式指示符(如"%d"表示整数)。

与getchar和putchar不同,scanf和printf可以处理各种不同类型的数据,并具有更强大的格式化输出功能。

 字符串函数——头文件 string.h

strlen —— lenth

size_t strlen(const char *s) ;

返回 s 的字符串长度(不包括结尾的 ' \0 ' ) 

#include<stdio.h>
#include<string.h>
int main(int argc,const char *argv[])
{
	char line[]="Hello";
	
	printf("strlen=%lu\n",strlen(line));  ——> 5
	printf("sizeof=%lu\n",sizeof(line));  ——> 6
	
	return 0;
}

 自己实现 strlen 

#include<stdio.h>
mylen(const char *s)
{
	int idx=0;
	while(s[idx]!='\0'){
		idx++;
	}
	return idx;
}
int main(int argc,const char *argv[])
{
	char line[]="hello";
	
	printf("mylen=%lu\n",mylen(line));
	
	return 0;
}

strcmp —— compare

int strcmp(const char *s1,const char *s2) ;

比较两个字符串

  • 返回值 = 0 : s1 == s2 ;
  • 返回值 > 0 : s1 > s2 ; 
  • 返回值 < 0 : s1 < s2 ; 

#include<stdio.h>
#include<string.h>
int main()
{
	char s1[]="abc";
	char s2[]="abc";
	printf("%d",strcmp(s1,s2));
	
	return 0;
}
输出0
#include<stdio.h>
#include<string.h>
int main()
{
	char s1[]="abc";
	char s2[]="Abc";
	printf("%d",strcmp(s1,s2));
	
	return 0;
}
输出32 ——> 大于 0 说明 s1 > s2 ,
           32 是 'a' 和 'A' 的差值

自己实现 strcmp 

#include<stdio.h>
int mycmp(const char *s1,const char *s2)
{
	int idx=0;
	while(s1[idx]==s2[idx]&&s1[idx]!='\0'){
		//if (s1[idx]!=s2[idx]){
		//	break;
		//}else if(s1[idx]=='\0'){
		//	break;
		//}优化
		idx++;
	}
	return s1[idx]-s2[idx];
}
//或者下面这种写法(优化)
int mycmp2(const char *s1,const char *s2)
{
	while(*s1 ==*s2 && *s1!='\0'){
		s1++;
		s2++;
	}
	return *s1-*s2;
} 
int main()
{
	char s1[]="abc";
	char s2[]="abc ";
	printf("%d\n",mycmp(s1,s2));
	printf("%d\n",mycmp2(s1,s2));
		
	return 0;
}

strcpy —— copy

char *strcpy(char *restrict dst,const char *restrict src) ;

把 src 的字符串拷贝到 dst(包括 ' \0 ' )

  • 注意是把后面的拷贝到前面

restrict 表明 src 和 dst 不重叠 (C99)

  • 返回 dst 

           为了让 strcpy 的结果能够投入给其他函数的参数,参与其他运算

复制一个字符串

当从函数参数得到一个字符串,这是一个指针,指向一个我不知道的地方,通过 strcpy 把他复制在我这里

char *dst =(char)malloc(strlen(src)+1) ;
//首先用 malloc 动态申请空间,而申请的空间长度为
//strlen(src)+1 ——> 包括结尾的'\0'
strcpy(dst,src) ;

自己实现strcpy

#include<stdio.h>
#include<string.h>
char *mycpy(char*dst,const char *src)
{
	int idx=0;
	while(src[idx]){
		dst[idx]=src[idx];
		idx++;
	}//这里没有把结尾的'\0'拷贝进去
	dst[idx]='\0'; 
	return dst;
}

//或者指针形式
char *mycpy(char*dst,const char *src)
{
	char *ret=dst;
	while(*src){
		*dst=*src;//或直接写成 *dst++=*src++ 
		dst++;
		src++;
	}
	*dst='\0'; 
	return ret; //对dst进行了++ 
}

//优化
char *mycpy(char*dst,const char *src)
{
	char *ret=dst;
	while(*dst++=*src++){
	}
	*dst='\0'; 
	return ret;  
}

strcat —— catenate

char *strcat (char *restrict s1,const char *restrict s2) ;

 把 s2 拷贝到 s1 后面,接成一个长字符串

  • 返回 s1 
  • s1 必须有足够空间

问题 

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 对 cpy 表示能够拷贝多少个字符

   对 cat 表示能够连上多少字符

   对 cmp 表示要比较两串字符的前几个字符

字符串搜索函数

字符串中找字符

strchr —— 从左向右

char *strchr(const char *s,int c) ;

strrchr —— 从右向左

char *strrchr(const char *s,int c) ;
  • 从左向右(从右向左)在字符串中寻找 c 第一次出现的位置 
  • 返回 指针  
  • 返回NULL,表示没有找到 

如何找第二个?

#include<stdio.h>
#include<string.h>
int main()
{
	char s[]="Hello";
	char *p=strchr(s,'l');
	p=strchr(p+1,'l');   //在 p 已经找出来之后,在 p 的基础上再进行寻找
	//printf("%s\n",p);   //仅用作提示
	
	return 0;
}

拷贝练习

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	char s[]="Hello";
	char *p=strchr(s,'l');    
	char *t=(char*)malloc(strlen(p)+1);
	strcpy(t,p);
	printf("%s\n",t);         
	free(t);
	
	return 0;
}

输出找到的 l 之前的字符

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	char s[]="Hello";
	char *p=strchr(s,'l'); 
	char c=*p;  //需要恢复则可以恢复
	*p='\0';   
	char *t=(char*)malloc(strlen(p)+1);
	strcpy(t,s);
	printf("%s\n",t);         
	free(t);
	
	return 0;
}

字符串中找字符串

strstr —— 字符串中找字符串 

char *strstr(const char*s1,const char *s2) ;

strcasestr —— 在寻找过程中忽略大小写

char strcasestr(const char *s1,const char *s2) ;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值