C——字符串

字符串

  • 定义:char *变量名 = “字符串的内容”; / char 变量名[] = “字符串的内容”;
    两种定义有区别:
    *变量名:字符串量,不可以修改
    变量名[]:字符串
    !字符串在内存中实际存储时,有额外的一个字符结束标志 ‘\0’,(e.g. h-a-r-d-‘\0’)

  • 打印:printf中占位符%s,或者直接puts(“字符串名/指向字符指针”)
    e.g. char *string = “hardworld”; /
    char string1[] = {‘h’,‘a’,‘r’,‘d’,‘w’,‘o’,‘r’,‘l’,‘d’};
    char string2[5] = {‘h’,‘a’,‘r’,‘d’};
    char string3[] = “hard”;
    1.printf("This is a string:%s\n",string);
    2.puts(string);
    1). 对于,定义未具体声明长度的字符串数组等于字符集合,且没加入结束标识符‘\0\(如上例string1),puts & printf输出有错误,有的编译器出现重复打印有的出现乱码,不要使用这种定义。 对于定义了具体长度的字符串数组(如chart string[5]= {'h','a','r','d'} ),所声明的长度要包括字符串和最后的 ‘\0’,否则出现同样的问题。另外!!,如果非要写chart string[5]= {'h','a','r','d'} 类型,自行在最后加上’\0’,这样不会导致使用库函数时出现问题(“string.h”库函数都考虑了字符串的‘\0’结束标志)

赋值字符串

  • 对于使用malloc开辟空间的字符指针,赋值一个字符串常量是正常的
  • 不可以对一个声明的字符数组进行直接(=号)赋值,如下代码段中注释部分,报错: error: assignment to expression with array type。不同于初始化(如下arry),因为c语言中不允许赋值的左值为一个数组(Assignment operator shall have a modifiable lvalue as its left operand. A modifiable lvalue is an lvalue that does not have array type, […]),可以使用strcpy/strncpy来赋值,或者对每个字符数组元素进行赋值
	char array[] = "hardworld";
	char arry[10] = "hardworld";
	char arr[10] ;
	strcpy(arr,"hardWorld");
	arr[0] = 'h';
	arr[1] = 'a';
	//arr = "hardworld";		// error: assignment to expression with array type
	scanf("%s",arr);
	

大小的计算:

strlen函数 & sizeof关键字

针对char string[] = "hard"; 情况

  • strlen
    1. 用于计算有效字符的长度(不包括’\0’,不考虑定义字符串数组中定义的长度)。
    2. 对于char 型指针定义的字符串, 其计算大小也是有效字符个数。
  • sizeof
    szieof(字符串名)(/sizeof(字符串名[0]))进行计算(/sizeof(字符串名[0])可忽略,char型为1字节)
    1. 对于将字符串直接赋值的未定义长的字符数组(如下代码中string),计算结果比字符个数多1 ,因为计算了‘\0’
    2. 该关键字方法计算字符串数组长度,对于下例string1赋值{'h','a','r','d'}类型的定义,其长度就是元素个数,因为对于系统这是一个字符型数组,字符只是数组中的元素。
    3. 对于*变量名定义的字符串,因为是指针类型而且指针变量内存中占8字节, 所以使用sizeof算大小时,无论字符串长短都为8
int main(){
	char string[] = "hard";
	char string1[] = {'h','a','r','d'};
	char string2[] = {'h','a','r','d','\0'};
	char *string3 = "world";

	
	puts(string1);				//错误输出
	printf("%s\n",string1);
	puts(string2);				//错误输出
	printf("%s\n",string2);
	printf("%s\n",string3);
	
	printf("string size:%d \n",sizeof(string)/sizeof(string[0]));
	printf("string1 size:%d \n",sizeof(string1)/sizeof(string1[0]));
	printf("string2 size:%d \n",sizeof(string2)/sizeof(string2[0]));
	printf("string3 size:%d \n",sizeof(string3)/sizeof(string3[0]));

	return 0;
}

输出

hardhard
hardhard
hard
hard
world
string size:5
string1 size:4
string2 size:5
string3 size:8

=================================================================================================

动态开辟字符串

malloc()

按需在堆(heap)上开辟内存空间

当后期需要扩大指向空间大小时,可以随时修改其大小,也可用于防止非法访问野指针导致的段错误。

int main(){
	char *p; //野指针
	p = (char *)malloc(sizeof(char)); //p具有具体内存指向
	*p = 's';				
	printf("%c\n",*p);
	
	p = (char *)malloc(sizeof(char)*17); //增大p指向的空间大小,之前指向断开
	strcpy(p,"hard world!");
	puts(p);
	return 0;
}
s
hard world!
  • 对于直接赋值值字符串常量的char型指针, 再赋值这会出现非法访问,(本来想这用free函数释放空间的,但程序跑飞,gdb调试报错了 Critical error detected c0000374,思考了一下发现是因为将指针指向字符串,那么就不是原来malloc的内存了,这篇文章有更详细解释。或者使用strcpy复制字符串就不会,可以通过重新使用malloc分配空间给指针(等于又开辟了一个堆空间),就可以赋新数据。或者定义指针指向malloc分配空间的指针,对这个指针操作,就可以对malloc申请的空间进行释放(如下例)
int main(){
	char *p; 
	p = (char *)malloc(sizeof(char)*1); //p具有具体内存指向
	char *s = p;
	
	s = "hard";				//字符串常量
	printf("%s\n",s);
	free(p);
	p = (char *)malloc(sizeof(char)*16);  //重新分配空间
	strcpy(p,"hard world!");
	puts(p);
	return 0;
}

输出正确

hard
hard world!

空间释放

malloc在堆(heap)上开辟空间,只有在程序结束时才会释放,当程序中有死循环时,反复malloc可能会耗尽计算机中的堆资源,造成内存泄漏!

free()
  • 原型 void free(void *ptr);
  • 释放使用calloc,malloc 或realloc所分配的内存空间
  • 防止悬挂指针(野指针一种)

e.g

int *p = (int *)malloc(sizeof(int));
free(p);

空间扩容

当malloc开辟的空间不够时,将超出大小的数据进行赋值会造成越界

realloc()
  • 原型 void *realloc(void *ptr,size_t size);
  • 返回值:该函数返回一个指针 ,指向重新分配大小的内存。如果请求失败,则返回 NULL
  • 尝试调整(扩大或者缩小)之前调用malloc或者calloc所分配的ptr指向的内存空间的大小,无论是扩张或是缩小,原有内存的中内容将保持不变,如果时缩小则可能导致原有内容丢失,但有时候编译器还是会打出完整的原始字符串,可以通过gdb调试检查缩小后丢失的字符
  • 扩容后首地址不变
int main(){
	char *p; 
	p = (char *)malloc(sizeof(char)*5); //p具有具体内存指向
	strcpy(p,"Hard");
	printf("before extend:%s\t\t%d\t%p\n",p,sizeof(p),p);
	p = realloc(p,sizeof("hardworld!"));
	
	strcpy(p,"hardworld!");	//(该字符串有11个字符(不包括'\0'))
	printf("after extend: %s\t%d\t%p\n",p,sizeof(p),p);

	free(p);
	puts("done!");
	return 0;
}

输出正常

before extend:Hard              8       0000012235aa1600
after extend: hardworld!        8       0000012235aa1600
done!

=================================================================================================

字符串常用API

gets

  • 库:“stdlib.h”
  • `char *gets(char * str);
  • 获取字符串输入
    e.g.
	char *str = (char*)malloc(sizeof(char)*128);
	gets(str);
	puts(str);

strcpy

  • 库:“string.h”
  • char *strcpy(char *dest, const char* src); dest:目标字符串,src被拷贝字符串
  • 拷贝包括终止空字符
    e.g. strcpy(string,"hard world!");

strcat

  • 库:“string.h”
  • char *strcat(char *dest, const char *src);dest目标字符串,src拼接字符串
  • 字符串的拼接
    e.g.
	strcpy(src,  "This is source");
	strcpy(dest, "This is destination");
 
 	strcat(dest, src);

strcmp,strncmp

  • “string.h”
  • int strcmp(const char *str1, const char *str2) / int strncmp(const char *str1, const char *str2, size_t n)
  • 字符串的比较,如果返回值小于 0,则表示 str1 小于 str2,如果返回值大于 0,则表示 str1 大于 str2,如果返回值等于 0,则表示 str1 与str2相同,(n表示比较的位数)
    e.g strcmp("hard","world");
    strncmp("hard","world",3);

strchr

  • “string.h”
  • char *strchr(const char *str, int c)
  • 寻找在str字符串中第一次出现c字符的位置,返回一个指针指向第一次出现的位置

strstr

  • “string.h”
  • char *strstr(const char *haystack, const char *needle)
  • 在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 ‘\0’

strlwr/ strupr

  • “string.h”
  • strlwr:char *strlwr(char *str);
  • strupr:char *strupr(char *str);
  • 前者将字符串str字母全部改为小写,后者将str中字符全部改为大写,返回修改后的字符串

strtok

  • “string.h”
  • char * strtok(char str[], const char *delims);
  • 分割字符数组str[],以delims为分割点,返回到分隔符之前的字符串
  • !只有第一次分隔str填写需要分割的数组,剩余的分割str[]需要填写为NULL,见下例
int main(){
	char arry[] = "This is typed Hard world";
	char *character[6];			//使用指针数组来存储分割的子字符串
	char **pArr = character;		

	 *pArr= strtok(arry," ");

	while(*pArr  != NULL){
	//因为已经存入了一个字符串,但指针没偏移,所以需要先偏移,后赋值
	//此处偏移相当于是pArr行数组偏移
		*++pArr = strtok(NULL, " ");	
	}

	pArr = character;		//返回首地址
	while(*pArr  != NULL){
		printf("   %s\t",*pArr++);
	}
	
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值