C语言_字符串的哪些事!

字符串或串(String)是由数字、字母、下划线组成的一串字符。一般记为 s=“a1a2···an”(n>=0)。它是编程语言中表示文本的数据类型。在程序设计中,字符串(string)为符号或数值的一个连续序列,如符号串(一串字符)或二进制数。

补充:字符串在存储上类似字符数组,它每一位单个元素都是能提取的。

定义字符串

编程练习:如何定义字符串

#include <stdio.h>
 
int main()
{
	//字符串既然叫做字符数组,就可以用定义数组的方法来定义它
	
	
	/*int a[5] = {12,13,14,15,16};
	
	for(int i=0;i<5;i++)				之前定义数组及其遍历方法							
	{
		printf("%d ",a[i]);
	}*/
	char cdata[5] = {'h','e','l','l','o'};	//打印时候最后可能有乱码,后面解决  
	
	//cdata2作为字符串变量(指针常量)可以用来修改里边的数值
	//pchar作为字符串常量(常量指针),不可以修改里边存放的值
	
	// 字符串变量
	char cdata2[] = "hello";		//前边的定义方式繁琐,采用后两种
	
	// 字符串常量,不允许修改。
	char *pchar = "hello";
	char c = 'c';		//定义一个字符的方法
	
	printf("%s",cdata2);//字符串打印
	
	putchar('\n') ; //输出一个字符
	printf("%s",pchar);//字符串打印
	
	putchar('\n') ; //输出一个字符
	puts(pchar); //输出多个字符
	
	// 修改字符串  
   //	*pchar = 'L'; 不能修改
	cdata2[2] = 'L';
	printf("%s",cdata2);
	
	/*
	for(int i=0;i<5;i++)
	{
		printf("%c",cdata2[i]);
		//printf("%c\n",*(pchar+i));	//遍历方式较为繁琐
	}*/
	
	
	/*char *p;		//*p是一个野指针,对野指针的赋值会发生段错误
	
	*p = 'm';
	puts("done\n");*/
	
	return 0;
}

注意:指针可以保存地址、修改指向、指向字符常量的地址空间;但操作野指针的地址空间是不可行的,会造成段错误!!!

常量指针本质上是一个指针,指针就是地址,它所指向的地址可变,但里边存放的值不可变;指针常量本质上是一个常量,它所指向的地址不可变,一旦定义就确定了它的地址,但里边存放的常量可以被修改。

存储方式:

字符串的存储方式:会在字符串的末尾加一个'\0'

代码验证:用sizeof计算字符串的长度


#include <stdio.h>
 
int main()
{
	//字符串的结束标志:'\0'
	//实际上字符在内存空间中的存储方式
	char cdata[] = {'h','e','l','l','0','\0'};	 //字符串的结束标志'\0' ,当用定义字符数组时,要注意在最后补'\0'
	
															
	char cdata2[] = "hello";		//定义字符串时会自动在后边补'\0'
	char *pchar = "hello";
	
	
	int len1 = sizeof(cdata2)/sizeof(cdata2[0]);
	int len2 = sizeof(cdata)/sizeof(cdata[0]);
	int len3 = sizeof(pchar)/sizeof(pchar[0]);
	printf("len1 = %d\n",len1);
	printf("len2 = %d\n",len2);
	printf("len3 = %d\n",len3);		//最后一个是表示OS操作系统用8字节来存放一个地址
	
	printf("%s\n",cdata);	//当没有'\0'的结束标志时,输出字符串就可能有乱码
	
	return 0;

}

strlen和sizeof的区别:

strlen是计算字符串的有效长度(不包含'\0'),sizeof是计算整个字符串的长度

编程验证:

#include <stdio.h>
#include <string.h>
 
void My_str()
{
	
}
 
int main()
{
	char str[] = "hello";
	char str2[128] = "hello";
	char *p = "hello";
	
	void (*p2)();
	p2 = My_str;
	
	printf("strlen of str:       %d\n",strlen(str));	//  5		//计算字符串的有效长度,不包含'\0'
	printf("sizeof of str:       %d\n",sizeof(str));	//	6	//计算整个字符串的长度
	
	printf("strlen of str2:      %d\n",strlen(str2));		//5	//计算字符串的有效长度,不包含'\0'
	printf("sizeof of str2:      %d\n",sizeof(str2));	//128	//计算整个字符串的长度
	
	printf("strlen of p:         %d\n",strlen(p));     //5    //计算字符串的有效长度,不包含'\0'
	
	printf("sizeof of p:         %d\n",sizeof(p));	//8	//以下都是指针变量,OS操作系统用8字节来存放一个地址
	printf("sizeof of int *:     %d\n",sizeof(int *));//8
	printf("sizeof of char *:    %d\n",sizeof(char *));//8
	printf("sizeof of p2:        %d\n",sizeof(p2));//8
	
	
	return 0;
}

动态开辟字符串

C 库函数 - malloc() 开辟内存空间,p有了固定的地址,不再是野指针

描述

C 库函数 void *malloc(size_t size) 分配所需的内存空间,并返回一个指向它的指针。

声明

void *malloc(size_t size)

参数:

  • size_t int 型
  • size -- 内存块的大小,以字节为单位。

返回值

该函数返回一个指针 ,指向已分配大小的内存。如果请求失败,则返回 NULL。

C 库函数 - calloc() 开辟内存空间

描述

C 库函数 void *calloc(size_t nitems, size_t size) 分配所需的内存空间,并返回一个指向它的指针。malloc 和 calloc 之间的不同点是,malloc 不会设置内存为零,而 calloc 会设置分配的内存为零。

声明

void *calloc(size_t nitems, size_t size)

参数

  • nitems -- 要被分配的元素个数。
  • size -- 元素的大小。

返回值

该函数返回一个指针,指向已分配的内存。如果请求失败,则返回 NULL。

C 库函数 - strcpy() 拷贝strcpy 将新数据放置到目标文件

描述

C 库函数 void *memset(void *str, int c, size_t n) 复制字符 c(一个无符号字符)到参数 str 所指向的字符串的前 n 个字符。

声明

void *memset(void *str, int c, size_t n)

参数

  • str -- 指向要填充的内存块。
  • c -- 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式。
  • n -- 要被设置为该值的字符数。

返回值

该值返回一个指向存储区 str 的指针。

C 库函数 - realloc() 扩容函数字符大小

描述

C 库函数 void *realloc(void *ptr, size_t size) 尝试重新调整之前调用 malloc 或 calloc 所分配的 ptr 所指向的内存块的大小。

声明

void *realloc (void *ptr, size_t size)

参数

  • ptr -- 指针指向一个要重新分配内存的内存块,该内存块之前是通过调用 malloc、calloc 或 realloc 进行分配内存的。如果为空指针,则会分配一个新的内存块,且函数返回一个指向它的指针。
  • size -- 内存块的新的大小,以字节为单位。如果大小为 0,且 ptr 指向一个已存在的内存块,则 ptr 所指向的内存块会被释放,并返回一个空指针。

返回值

该函数返回一个指针 ,指向重新分配大小的内存。如果请求失败,则返回 NULL。

memset

编程练习:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
	/*char *p ;  //野指针
	p ='a';
	puts("end")  // 这里是野指针 puts语句就不会被执行*/
	
	char *p;
	p = (char *)malloc(1);  //malloc开辟内存空间,p有了固定的地址,不再是野指针
	
	*p = 'c';
	free(p);				//防止堆空间被耗尽,将malloc/calloc分配的空间释放掉
    
	p = NULL;    // 如果空间释放后,没有新的内存空间,就需要将 指针赋值为空 ,防止成为野指针。
	p = (char *)malloc(12);
	
	if (p == NULL){
		printf("malloc error\n");
		exit(-1);
	}
	 memset(p,'\0',12);  // 通过memset函数将12个字符清理,初始成\0;
	      // 目标地址 , 新文件
	strcpy(p,"liuxianglong"); //    将新数据放置到目标文件
	
	printf("扩容地址 : %x\n" ,p);
	
	int len = strlen("liuliuxianglong1234546317789654");  //计算字符串有多少字符
	
	int newlen = len - 12 + 1; //(+1  是给\0留个位置)
	 
	realloc(p,newlen);// realloc 扩容函数字符
	printf("扩容地址 : %x\n" ,p);
	strcpy(p,"liuxianglong1234546317789654"); //12个字符,放不下这么多字节 拷贝strcpy 
	

	printf("%c\n",*p);  //输出(1)
	printf("%s\n",p);  //输出(12)
	
	puts(p);       //输出(12)
	
	
	puts("end");
	
	
	return 0;
}

字符串输出 printf
#include <stdio.h>
// 输出字符串
int main()
{
	
	char *p = "liuxiaglong";
	
	
	printf("请输出字符串\n");
	puts(p);  //puts函数自带换行符
	

    return 0 ;
}
	

获取字符串:scanf
#include <stdio.h>
// 输出字符串
int main()
{
	
	char *p = "liuxiaglong";
	
	printf("请输出字符串\n");
	puts(p);  //puts函数自带换行符
	
	
	char str[128] = {'\0'};
	
	printf("请输入字符串\n");
	scanf("%s",str); //字符串输出
	puts(str);
	
	
	return 0;

}

获取字符串 gets
#include <stdio.h>
// 输出字符串
int main()
{
	
	char *p = "liuxiaglong";
	
	
	printf("请输出字符串\n");
	puts(p);  //puts函数自带换行符
	
	char str1[128] = {'\0'};
	
	printf("请输入字符串2\n");
	
	//scanf("%s",str); //字符串输出
	gets(str1);
	puts(str1);

	return 0;

}

注意:sanf 和gets不能同时出现在一个模块函数内!

gets用于从标准输入中读取字符串,

scanf用于从标准输入中读取格式化输入,包括整数、浮点数等。

计算字符有效长度

编程说明:计算有效字符的长度:strlen(不包括'\0')

#include <stdio.h>
#include <string.h>
// 获取字符串的有效长度
int main()
{

	char str[128] = "hello world";
	
	// 获取字符串的有效长度
	int len1 = strlen(str);
	
	printf("len1 = %d\n",len1);
	
	// 获取字符串的全部长度
	int len2 = sizeof(str);
	
	printf("len2 = %d\n",len2);
	
	return 0;

}

字符串拷贝

编程说明:字符串拷贝:strcpy strncpy的区别

/*
	用strcpy实现字符串的全部拷贝  strncpy函数是部分拷贝
*/
 
//char *strcpy(char *dest, const char *src)
#include <stdio.h>
#include <string.h>
 
int main()
{
	char str[128] = {'\0'};
	char *p = "makabaka handsome";
	  
	strcpy(str,p);  //stpcpy函数是全部拷贝
	
	puts(str);
	return 0;
}

/*  
	用strncpy实现字符串的拷贝    可指定字符串的字符长度
*/
 
//char *strncpy(char *dest, const char *src, size_t n)
#include <stdio.h>
#include <string.h>
 
int main()
{
	char str[128] = {'\0'};
	char *p = "makabaka handsome";
	
	strncpy(str,p,8);  // 指定拷贝8个字符到目标函数中去
	
	puts(str);
	return 0;
}

由此可见:strcpystrncpy 的区别是

strncpy可以指定要拷贝多少个字符到目标函数中去,

strcpy只可以拷贝所有的字符到目标函数中。

#include <stdio.h>
//strcpy 的原型函数

          // 两个参数 形参,原字符
char* myStrcpy(char *des, char *src)
{
	//if的作用是现计算表达式 形参,如果其值为假(即为0),
	
	if(des == NULL || src == NULL){
		return NULL;
	}
	
	char *bak = des;  // char一个备份地址,去保存目标地址,因为需要进行赋值。
	
	while( *src != '\0'){
		*des = *src;  //先赋值
		
		 // 在偏移
		des++;
		src++;
	}
	*des = '\0';   // 结束标准
	
	return bak;
}


         // 两个参数 形参,原字符
char* myStrcpy2(char *des, char *src)
{
	
	if(des == NULL || src == NULL){
		return NULL;
	}
	
	char *bak = des;  // char一个备份地址,去保存目标地址,因为需要进行赋值。
	
	while( *src != '\0'){
		*des++ = *src++;  //先赋值,在偏移
		
		
	}
	*des = '\0';   // 结束标准
	
	return bak; 
}

char* myStrcpy3(char *des, char *src)
{
	
	if(des == NULL || src == NULL){
		return NULL;
	}
	
	char *bak = des;  // char一个备份地址,去保存目标地址,因为需要进行赋值。
	 
	         //先赋值, 在循环
	while( (*des++ = *src++) != '\0');    
	
	*des = '\0';   // 结束标准
	
	return bak;
}

int main()
{
	char str[128] = {'\0'};
	
	
	char a = 'm';
	char b ;
	if ((b = a )== 'm'){  //测试能否先赋值 ,在进行if判断
		
		
		printf("ok\n");
	}
	
	char *p  = "liuxiaglong  handsome";
	
//	myStrcpy(str,p);//stpcpy函数是全部拷贝
	myStrcpy3(str,p);//stpcpy函数是全部拷贝
	puts(str);
	return 0;
}

#include <stdio.h>
//strncpy 的原型函数

          // 三个参数 形参,原字符 ,字符数
char* myStrncpy(char *des, char *src,int count)
{
	//if的作用是现计算表达式 形参,如果其值为假(即为0),
	if(des == NULL || src == NULL){
		return NULL;
	}
	
	char *bak = des;  // char一个备份地址,去保存目标地址,因为需要进行赋值。
	
	while( *src != '\0' && count >0){
		*des = *src;  //先赋值
		 // 在偏移
		des++;
		src++;
		
		count--;
		
	}
	
	// 如果count 设定成了20个字符,原字符只有15个, *src = '\0'的情况下,将其他没有的字符将输出成'\0';
	if(count >0){
		while(count > 0){
			count -- ;
			* des = '\0';
		}
	}
	*des = '\0';   // 结束标准
	
	return bak;
}


 
int main()
{
	char str[128] = {'\0'};
	
	
	char a = 'm';
	char b ;
	if ((b = a )== 'm'){  //测试能否先赋值 ,在进行if判断
		
		
		printf("ok\n");
	}
	
	char *p  = "liuxiaglong  handsome";
	
	myStrncpy(str,p,5);//stpcpy函数是拷贝指定多少个字符
	
	puts(str);
	return 0;
}

#include <stdio.h>
//strncpy 的原型函数

          // 三个参数 形参,原字符 ,字符数
char* myStrncpy(char *des, char *src,int count)
{
	//if的作用是现计算表达式 形参,如果其值为假(即为0),
	if(des == NULL || src == NULL){
		return NULL;
	}
	
	char *bak = des;  // char一个备份地址,去保存目标地址,因为需要进行赋值。
	
	while( *src != '\0' && count >0){
		*des = *src;  //先赋值
		 // 在偏移
		des++;
		src++;
		
		count--;
		
	}
	/*
	 如果count 设定成了25个字符,原字符只有10个,
    *src = '\0'的情况下,将其他没有的字符将输出成'\0';      */
	if(count >0){
		while(count > 0){
			count -- ;
			* des++ = '\0';
			printf("ok\n");  //这里的ok将会输出4次。
		}
		return des ;
	}
	*des = '\0';   // 结束标准
	
	return bak;
}

int main()
{
	char str[128] = {'\0'};
	
	char *p  = "liuxiaglong  handsome";
	
	myStrncpy(str,p,25);//stpcpy函数是拷贝指定多少个字符
	
	puts(str);
	return 0;
}

断言(assert)

assert() 的用法像是一种"契约式编程",其表达的意思就是,程序在假设条件下,能够正常良好的运作,其实就相当于一个 if 语句。

但是这样写的话,就会有无数个 if 语句,甚至会出现,一个 if 语句的括号从文件头到文件尾,并且大多数情况下,我们要进行验证的假设,只是属于偶然性事件,又或者我们仅仅想测试一下,一些最坏情况是否发生,所以这里有了 assert()。

assert 宏的原型定义在 assert.h 中,其作用是如果它的条件返回错误,则终止程序执行。

assert 的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向 stderr 打印一条出错信息,然后通过调用 abort 来终止程序运行。(第二个代码)

编程说明:断言(assert)函数的运用

#include <stdio.h>
#include <assert.h>
//assert 断链的原型函数

          // 2个参数 形参,原字符 ,字符数
char* myStrcpy(char *des, char *src)
{
	
	
	*if(des == NULL || src == NULL){
		return NULL;
	}
	
	char *bak = des;  // char一个备份地址,去保存目标地址,因为需要进行赋值。
	
	while( *src != '\0' ){
		*des = *src;  //先赋值
		 // 在偏移
		des++;
		src++;
		
	}
	
	*des = '\0';   	// 添加字符串终止符
	
	return bak;
}

int main()
{
	char str[128] = {'\0'};

	char *p  = "liuxiaglong  handsome";
	
	myStrcpy(str,p);
	
	puts(str);
	return 0;
}

当字符串指针为空时, assert函数启用

断言 输出 :

如果 pdes 和src为空时 程序结束,并且提示des != NULL && src != NULL 这句话

#include <stdio.h>
#include <assert.h>
//strcpy 的原型函数

          // 2个参数 形参,原字符 ,
char* myStrcpy(char *pdes, char *src)
{
	//if的作用是现计算表达式 形参,如果其值为假(即为0),
	assert(pdes != NULL && src != NULL);
	
	/*if(des == NULL || src == NULL){
		return NULL;
	}*/
	
	char *bak = pdes;  // char一个备份地址,去保存目标地址,因为需要进行赋值。
	
	// 将源字符串拼接到目标字符串的末尾
	while( *src != '\0' ){
		*pdes = *src;  //先赋值
		 // 在偏移
		pdes++;
		src++;
		
	}
	// 添加字符串终止符
	*pdes = '\0';   // 结束标准
	
	return bak;
}
 
int main()
{
	char str[128] = {'\0'};
	char *pstr = NULL;
	char *p  = "liuxiaglong  handsome";
	
	myStrcpy(pstr,p);
	
	puts(str);
	return 0;
}

字符串拼接
编程说明:字符串拼接 strcat
#include <stdio.h>
/*
	用strcat实现字符串的拼接
*/
 
#include <string.h>
 
int main()
{
	// 无返回值 ,一般情况下不需要返回值
	char str[] = "hello";
	char *p = "World";
	
	strcat(str,p);
	
	puts(str);
	
	return 0;
}

strcat_有返回值

#include <stdio.h>
/*
	用strcat实现字符串的拼接
*/
 
#include <string.h>
 
int main()
{
	// 无返回值 ,一般情况下不需要返回值
	char str[] = "hello";
	char *p = "World";
	
	strcat(str,p);
	
	puts(str);
	
	printf("----------\n");
	
	//有返回值
	
	char str1[] = "hello1";
	char *p1 = "World1";
	char *p2;
	p2 = strcat(str1,p1);
	
	puts(p2);
	return 0;
}

自定义函数实现字符串拼接
#include <stdio.h>
/*
	用strcat实现字符串的拼接
*/

 
#include <string.h>

// 自定义函数实现字符串拼接,参数为目标字符串des和源字符串src
char* myStrcat(char *des, char *src) 
{
	char *bak = des;  // 定义一个指针,拷贝des
	
	// 查找目标字符串的末尾 
	while(*des !='\0'){
		
	des++;  //如果末尾的不是\0 就++
	}
	
	// 将源字符串拼接到目标字符串的末尾
	while((*des++ = *src++) != '\0');
	
	// 添加字符串终止符
	*des = '\0';
	
	return bak;  // 返回拼接后的字符串的起始地址
}
 
int main()
{
	// 无返回值 ,一般情况下不需要返回值
	char str[] = "hello";
	char *p = "World";
	
	strcat(str,p); // 将p拼接到str的末尾
	
	puts(str);// 打印拼接后的字符串
	
	printf("----------\n");
	
	//有返回值
	// 使用自定义函数进行字符串拼接
	char str1[] = "hello2";
	char *p1 = "World2";
	char *p2;
	p2 = myStrcat(str1,p1); 调用自定义函数拼接字符串
	
	
	
	puts(p2); // 打印拼接后的字符串
	return 0;
}

字符串比较

编程说明: 字符串比较:strcmp strncmp 的区别

strcmp比较整个字符串,而strncmp比较指定的前n个字符。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int main()
{
	char *p1 = "happyn";
	char *p2 = "happym";
		  
	  //     strcmp 函数,p1和p2进行比较 p1小 输出-1 ,p1大 输出1,相对输出0;
	int ret =strcmp(p1,p2);
	
	if(ret == 0){
		printf("p1 and p2 是相等的");
	}
	
	printf("RET = %d\n",ret);
	return 0;
}

/*
	strncmp的功能:比较指定字符串的大小
*/
 
//int strncmp ( const char * str1, const char * str2, size_t n )
 
#include <stdio.h>
#include <string.h>
int main()
{
	
	
	/*
		功能是把 str1 和 str2 进行比较,最多比较前 n 个字节,
		若str1与str2的前n个字符相同,则返回0;
		若s1大于s2,则返回大于0的值;
		若s1 小于s2,则返回小于0的值。
	*/
	
	char *p1 = "happywworld";
	char *p2 = "happymworld";
	  
	int ret =strncmp(p1,p2,7);
	
	if(ret == 0){
		printf("p1 and p2 是相等的");
	}
	
	
	printf("n = %d\n",ret);
	
	return 0;
}

  • 11
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值