字符串操作总结

字符串的初始化

  • 字符数组

(1) char str[10]={'j','u','l','i','a','n'}
申明固定长度的字符数组,如果赋值长度大于数组长度,报错;如果小于数组长度,后面都是0(即‘\0’)

(2)char str[10]={"julain"}
(3)char str[10]="julian"

后两个结果一样,当成字符串去初始化,最后一位是str[6] =’\0’



(4)char str[]={'j','u','l','i','a','n'}
与(1)对比,如果定义成隐式长度,则长度会以后面的字符数来决定。数组最后一个是’n’,不是’\0’。

(5)char str[]={"julian"}
(6)char str[]="julian"
后两个是一样的,当成字符串处理,str数组的长度是julian+\0,即7。str不能再被其他字符串赋值。


  • 字符串指针

(1) char* str="julian"

(2)char* str; str="julian"
这种将字符串赋值给指针是OK的,它可以再被其他字符串赋值。能以str[]方式来访问,但不能修改。str可以再被指向其他字符串常量,或者字符串数组。



char* 和char[] 的区别

char* str ="julian" "julian"存放在常量区,是无法修的,但是str可以再指向其他内容。但是定义char str[]="julian" 这种形式的,字符串数组是在栈中分配的,可以修改数组内容的。

(1) 读写能力

  1. char* str ="julian"; 此时"julian"存放在常量区。通过指针只可以访问字符串常量,而不可以改变它。
  2. char str[]="julian"; 此时 "julian"存放在栈。可以通过指针去访问和修改数组内容。

(2) 首指针的可修改性

  1. char* str ="julian"; str指向常量的首地址,可以通过str[]去逐个访问字符,str指向可以改变的,比如
char* str="julian";
char str1[]="kerr";
str=str1;
printf("%s",str); // 编译通过,结果是kerr,也可以通过str去改变kerr的内容
  1. char str[]="julian";str指向第一个元素(即j的地址),一经分配就str不能更改,比如:
char* str="julian";
char str1[]="kerr";
str1=str; //报错

(3)赋值时刻

  1. char* str ="julian"; 编译的时候就确定了,因为是常量。
  2. char str[]="julian";在运行的时候确定,在栈中。

(4)存取效率

  1. char* str ="julian"; 存于只读数据区(.rodata常量区),慢。
  2. char str[]="julian"; 存于栈上。快。


字符串处理函数

注意:字符数组dest必须是数组名形式,不能是字符串指针,(其实如果char* p指向的不是常量,而是指向栈区分配的数组,也是可以的),src可以是数组名也可以是字符串常量 ,dest要能够容纳src
下面介绍的函数基本都需要注意红色部分


字符串的输入输出函数

  1. scanf()    printf()  在头文件<stdio.h>
  • 格式说明:
符号含义
%d十进制有符号整数
%u十进制无符号整数
%f浮点数
%s字符串
%c单个字符
%p指针的值
%e指数形式的浮点数
%x, %X无符号以十六进制表示的整数
符号含义
%9.2f浮点数, 其中小数位为2, 整数位为7,
%3d表示输出3位整型数, 不够3位,右对齐
%-3d- 表示左对齐
%03d表示输出3位整型数, 不够3位,左补0,右对齐
%8s表示输出8个字符的字符串, 不够8个字符,右对齐
typedef struct PERSON
{
	int ID;
	char name[64];
}Person;

int main(void)
{
	Person p1;
	scanf("%d %s",&p1.id,p1.name); //""之间除了格式不要加符号 
	printf("%d , %s",p1.id,p1.name);
return 0;
}
输入:1 julian
输出:1 ,julian

注意:假如name是 Julian Andrison ,输入name只是Julian,因为scanf遇到第1个空白(空格、制表符,换行符)时,就不会再读取输入



  1. puts()    gets()  在头文件<string.h>
  • 可以读字符串(可以包含空格),编译器会提示警告,说使用它不安全,使用时,保证存的buffer足够大来容纳读取的字符串
char str[64];
gets(str);
puts(str);


字符串拷贝、追加


  1. char *strcpy(char * dest, const char *src);   <string.h>和<stdio.h>
    功能:将src地址开始且包含’\0’结束符的字符串复制到以dest开始的空间
    库原型:
char* strcpy(char* des,const char* source)
{
 
 char* r=des;
   
  assert((des != NULL) && (source != NULL));
 
 while((*r++ = *source++)!='\0');
 
 return des;
 
}


  1. char *strncpy(char *dest,char *src,int size_t n);   <string.h>
    功能:把src所指向的字符串中以src地址开始的前n个字节复制到dest所指的数组中,并返回被复制后的dest。
char str[64]="julian";
char*p = "kerr";
strncpy(str,p,4);
printf("%s"str);  输出kerran

strncpy(str,p,5);
printf("%s"str);  输出kerr


  1. char *strcat(char *dest,const char *src);  <string.h>
    功能: 把src中的内容复制到dest结尾处(覆盖’\0’)。
char str[64]="julian";
char*p = "kerr";
strcat(str,p);
printf("%s",str); 输出juliankerr


  1. char * strncat(char *dest, const char *src, size_t n);
    功能:把src所指字符串的前n个字符添加到dest所指字符串的结尾处,并覆盖dest所指字符串结尾的’\0’
char str[64]="julian";
char*p = "kerr";

//strcat(str,p,4);
strcat(str,p,5);
printf("%s",str); 两种情况都输出juliankerr,因为str[64]后面没赋值都是0


字符串比较

  1. int strcmp(const char *s1,const char *s2);    <string.h>
    功能:比较两个字符串,
    若s1==s2,则返回零;
    若s1<s2,则返回负数;
    若s1>s2,则返回正数
char str1[]= "julian";
char* str2="mike";
int i=strcmp(str1,str2);
printf("%d",i);  输出是:-3(即比较的不同字母的ascii差值)


  1. int strncmp ( const char * str1, const char * str2, size_t n );  <string.h>
    功能:比较指定长度字符串
    返回值:和上面一样


  1. int strcasecmp(const char *s1,const char *s2); (linux下的函数,windows下使用_stricmp)    <string.h>
    功能:忽略大小写比较字符串
    返回值:和上面一样



  2. int strncasecmp(const char *s1,const char *s2); (linux下的函数,windows下使用_strnicmp)    <string.h>
    功能:忽略大小写比较字前n个字符
    返回值:和上面一样



字符串查找

  1. char* strchr(const char*string, char c)   <string.h>
    功能:查找字符串 string 中首次出现字符 c 的位置
    返回值:成功则返回要查找字符第一次出现的位置(指针),失败返回NULL
char str[]="julian";
char* pos=strchr(str,'n');
printf("%c",*pos);  输出:n


  1. char strrchr(const char string, int c);    <string.h>
    功能:查找字符c在字符串string中最后一次出现的位置, 也就是对string进行反序搜索, 包含NULL结束符.
    返回值:返回一个指针, 指向字符c在字符串string中最后一次出现的位置, 如果没有找到, 则返回NULL.
char str[]="qweu13ll23i3mi";
char* p = strrchr(str,'3');
printf("%c",*(p+1));  //最后一个3后面是'm' ,输出:m


  1. char *strstr(const char *str1, const char *str2);   <string.h>
    功能:判断字符串str2是否是str1的子串
    返回值:如果是子串,返回str2在str1中首次出现的地址;否则,返回NULL。
char str1[]="julian";
char str2[]="lian";
char* pos=strstr(str1,str2);
printf("%s",pos);   输出lian


  1. int strspn(const char *current, const char *accept)   <string.h>
    功能:以目标字符串accept的所有字符作为集合,在当前字符串current查找不属于该集合的第一个元素的偏移
    返回值:偏移值n(也可以理解current字符串中前n个字符在accept里面),第n+1个不在了
char str[]="jul123";
int num = strspn(str,"jdjiu,2341"); // "jul123"第一个不在"jdjiu,2341"  集合里面的是l,所以返回:2
printf("%d",num); //num:2


  1. int strcspn(const char *current, const char *accept)   <string.h>
    功能:以目标字符串accept的所有字符作为集合,在当前字符串current查找属于该集合的第一个元素的偏移
char str[]="qweul123";  
int num = strcspn(str,"jdjiu,2341"); //"qweul123"中的u是第一个属于"jdjiu,2341"字符串的,所以num=3
printf("%d",num); //num=3


  1. char * strpbrk(const char* current, const char* accept)   <string.h>
    功能:以目标字符串accept的所有字符作为集合, 在当前字符串current查找属于该集合的第一个元素,并返回地址
    返回值:返回current中第一个满足条件的字符的指针,如果没有匹配字符则返回空指针NULL。
char str[]="qweul123"; 
char* p=strpbrk(str,"jdjiu,239"); //"qweul123"中的u是第一个属于"jdjiu,2341"字符串的,所以返回u的地址
printf("%c",*p); //u


字符串到数值类型的转化

  1. int atoi(const char *nptr)   <stdlib.h>
    功能:跳过前面的空白字符(例如空格,tab缩进),把字符串转换成整型数
    返回值:遇到非数字的字符就停止转化,返回之前的转化结果,“1y.34” -> 1
char str[]="123";
int i=atoi(str);
printf("%d",i);  输出:123


  1. int atof(const char *nptr)   <stdlib.h>
    功能:把字符串转换成浮点数
    返回值:float型浮点数,“123.123” 输出不一定是123.123,转成float型,小数点位数变化
char str[]="123.123";
float res=atof(str);
printf("%f",res); 输出:123.123001


  1. long atol(const char* nptr);  <stdlib.h>
    功能:把字符串转换成 long 型


  1. double strtod(const char* nptr, char ** endptr);   <stdlib.h>
    功能:把字符串转换成 double型,如果遇到不能转的字符,并将后续的字符串指针存储到 endptr指向的 char* 类型存储,如果不需要填NULL。
char str[]="1t3.a32";  //可以"1001e-2" 形式,输出是10.01
char*p;
double val=strtod(str,&p);
printf("%f",val); 输出:1.000000
printf("%s",pos);  输出:t3.a32


  1. long int strtol(const char* nptr, char** endptr, int base);  <stdlib.h>
    功能:从字符串 nptr 中转换 long 类型整型数值,endptr和上面一样,base :将字符串当成什么进制来处理。
    base:0 根据字符串前缀来识别,0:当做8进制处理,0x:当成16进制处理,都不是就是10进制处理
    base:2-32 指定当成什么进制处理
char str[]="1001";
int val = strtol(str,NULL,0);  val:1001
int val = strtol(str,NULL,2);  val:9
int val = strtol(str,NULL,8);  val:513
int val = strtol(str,NULL,10); val:0一样,1001
int val = strtol(str,NULL,16); val:4097

int val = strtol("01001",NULL,0);  val:513
int val = strtol("0x1001",NULL,0);  val:4097


  1. unsigned long strtoul(const char* nptr, char** endptr, int base);
    功能:从字符串 nptr 中转换unsigned long 类型整型数值 ,其他和上面一样


memry操作

  1. void* memset(void *dest, int value, size_t count);   <string.h>
    功能:将dest前面count个字节置为value.
    返回值:dest的值.
char str[10];
for(int i=10; i<10; i++)
{
	printf("%d",str[i]);  因为申明的str在栈上,没有初始化,野值
}

memset(str,0,10,);
for(int i=10; i<10; i++)
{
	printf("%d",str[i]);  经过memset之后,值都是0
}


note:常见错误
(1) memset函数按字节对内存块进行初始化,所以不能用它将int数组初始化为0和-1之外的其他值(除非该值高字节和低字节相同)。
(2)memset(void *dest, int value, size_t count);中value实际范围应该在0~~255,因为该函数只能取ch的后八位赋值给你所输入的范围的每个字节。
(3)容易弄反 value 和 count的顺序
(4)过渡使用memset。

char buffer[4];
memset(buffer,0,sizeof(char)*4);
strcpy(buffer,"123");
//"123"中最后隐藏的'\0'占一位,总长4位。memset是多余的. 因为这块内存马上就被全部覆盖,清零没有意义

char buffer[20];
memset(buffer,0,sizeof(char)*20);
memcpy(buffer,"123",3);
//这一条的memset并不多余,memcpy并没把buffer全部覆盖,如果没有memset,
//用printf打印buffer会有乱码甚至会出现段错误。
//如果此处是strcpy(buffer,"123");便不用memset,
//strcpy虽然不会覆盖buffer但是会拷贝字符串结束符

(5)传参过程中的指针降级

typedef struct PERSON
{
	int ID;
	char name[64];
}Person;

void func(Person* p)
{
	printf("%d",sizeof(p));  //64位机,8,地址的大小
}



  1. void* memcpy(void *dest, const void *src, size_t count);   <string.h>
    功能:从src复制count字节的数据到dest. 不能处理src和dest出现重叠.
    返回值:dest的值.
typedef struct PERSON
{
	int ID;
	char name[64];
}Person;

int mian(void)
{
	Person p1={1,"julian"};
	Person p2;
	
	memcpy(&p2,&p1,sizeof(p1));
	printf("%s's ID is %d \n" p2.name,p2,id);
	return 0;
}
输出:julian's ID is 1
  • strcpy和memcpy主要有以下3方面的区别。
    1、复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
    2、复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。
    3、用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值