C语言字符串

 

目录

字符串引入:

定义字符串:

 存储方式:

 strlen和sizeof的区别:

  动态开辟字符串

字符串常用操作函数:

输出字符串

获取字符串 

计算字符有效长度 

字符串拷贝 

 断言(assert)

 字符串拼接

 字符串比较

查找子字符

查找子字符串

 字符串分割


字符串引入:

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

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

定义字符串:

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

#include <stdio.h>

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

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

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

 存储方式:

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

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

#include <stdio.h>

int main()
{
	//字符串的结束标志:'\0'
	
	char cdata[] = {'m','a','k','a','b','a','k','a','\0'};	//实际上字符在内存空间中的存储方式
															//当用定义字符数组时,要注意在最后不'\0'
	char cdata2[] = "makabaka";		//定义字符串时会自动在后边补'\0'
	char *pchar = "makabaka";
	
	
	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[] = "Welcome";
	char str2[128] = "makabaka";
	char *p = "Welcome";
	
	void (*p2)();
	p2 = My_str;
	
	printf("strlen of str:       %d\n",strlen(str));			//计算字符串的有效长度,不包含'\0'
	printf("sizeof of str:       %d\n",sizeof(str));			//计算整个字符串的长度
	
	printf("strlen of str2:      %d\n",strlen(str2));			//计算字符串的有效长度,不包含'\0'
	printf("sizeof of str2:      %d\n",sizeof(str2));			//计算整个字符串的长度
	
	printf("strlen of p:         %d\n",strlen(p));
	printf("sizeof of p:         %d\n",sizeof(p));		//以下都是指针变量,OS操作系统用8字节来存放一个地址
	printf("sizeof of int *:     %d\n",sizeof(int *));
	printf("sizeof of char *:    %d\n",sizeof(char *));
	printf("sizeof of p2:        %d\n",sizeof(p2));
	
	
	return 0;
}

  动态开辟字符串

C 库函数 - malloc()

描述

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

声明

void *malloc(size_t size)

参数

  • 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()

描述

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。

编程练习:用malloc和calloc动态开辟字符串,realloc重新分配内存空间

/*
	用malloc分配空间并初始化,并且实现字符串的拷贝
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// void *malloc(size_t size)
//void free(void *ptr)
// void *memset(void *str, int c, size_t n)
//char *strcpy(char* dest, const char *src);

int main()
{
	char *p;
	p = (char *)malloc(1);	//malloc开辟内存空间,p有了固定的地址,不再是野指针
	*p = 'c';
	free(p);				//防止堆空间被耗尽,将malloc/calloc分配的空间释放掉
	
	p = NULL;				
	p = (char *)malloc(10);	
	if(p == NULL)			//如果malloc正常分配空间,p就不会返回空值
	{
		printf("malloc error");
		exit(-1);
	}
	
	memset(p,'\0',10);		//将malloc分配到的空间进行初始化,全部初始化成0
	strcpy(p,"makabaka");	//将"makabaka"拷贝到p所指向的内存空间里
	
	printf("%s\n",p);
	puts("end");
	
	/*char *p;	//p是野指针,不能对其进行赋值操作,会出现段错误
	
	*p = 'c';
	printf("%c\n",*p);
	puts("end");*/
	
	
	return 0;
}

/*
	用realloc重新分配malloc或者calloc之前所分配的内存空间
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// void *malloc(size_t size)
// void *realloc(void *ptr, size_t size)
//void free(void *ptr)
// void *memset(void *str, int c, size_t n)
//char *strcpy(char* dest, const char *src);

int main()
{
	char *p;
	char str[] = "balabalabalablalabalmakabakamakabakamakabakamakabna";

	p = NULL;
	p = (char *)malloc(10);
	if(p == NULL)
	{
		printf("malloc error");
		exit(-1);
	}
	memset(p,'\0',10);
	
	int len = strlen(str);  				//计算有效字符的长度
	int newlen = len - 10 + 1;				//还需开辟新的内存空间+1(用来存放字符的结束标志)
	realloc(p,newlen);						//重新分配空间给p
	
	strcpy(p,str);
	printf("%s\n",p);
	
	return 0;
}

/*
	用calloc分配内存空间,而且用strcpy实现字符串的拷贝
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// void *malloc(size_t size)
// void *calloc(size_t nitems, size_t size) 
//void free(void *ptr)
// void *memset(void *str, int c, size_t n)
//char *strcpy(char* dest, const char *src);

int main()
{
	char *p;								//野指针
	p = (char *)calloc(1,sizeof(char));		//用calloc给p开辟空间,p有固定的地址,不再是野指针
	*p = 'c';
	free(p);								//释放calloc分配的空间
	p = NULL;
	p = (char *)calloc(10,sizeof(char));
	if(p == NULL)
	{
		printf("calloc error");
		exit(-1);
	}
	strcpy(p,"makabaka");
	
	printf("%s\n",p);
	puts("end");
	
	return 0;
}

/*
	用realloc重新分配malloc或者calloc之前所分配的内存空间
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
	char *p;
	char str[] = "balabalabalablalabalmakabakamakabakamakabakamakabna";
	
	p = (char *)calloc(1,sizeof(char));
	*p = 'c';
	free(p);
	
	p = NULL;
	p = (char *)calloc(10,sizeof(char));
	if(p == NULL)
	{
		printf("calloc error");
		exit(-1);
	}
	int len = strlen("balabalabalablalabalmakabakamakabakamakabakamakabna");
	int newlen = len - 10 + 1;
	realloc(p,newlen);
	strcpy(p,str);
	
	printf("%s\n",p);
	puts("end");
}

字符串常用操作函数:

输出字符串

编程说明:输出字符串:puts printf

/*
	用puts和printf输出字符串
*/

#include <stdio.h>

int main()
{
	char *p = "Welcome come to C world!";
	
	puts(p);
	printf("%s\n",p);
	
	return 0;
}

获取字符串 

 编程说明:获取字符串:scanf gets

/*
	用scanf和gets获取字符串的输入
*/

#include <stdio.h>

int main()
{
	char str[128] = {'\0'};
	
	puts("请输入字符串");
	//scanf("%s",str);
	gets(str);
	
	puts("输出字符串");
	
	puts(str);
	printf("%s\n",str);
	
	return 0;
}

计算字符有效长度 

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

/*
	用strlen计算字符串的有效长度,不包括'\0'
*/

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

int main()
{
	char str[128] = "makabaka";
	
	int len = strlen(str);
	
	printf("len = %d\n",len);
	return 0;
}

字符串拷贝 

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

/*
	用strcpy实现字符串的拷贝
*/

//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);
	
	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);
	
	puts(str);
	return 0;
}

 由此可见:strcpystrncpy 的区别是strncpy可以指定要拷贝多少字符到目标函数中去,strcpy只可以拷贝全部字符到目标函数中。

编程说明:自己编写函数实现strcpy 和 strncpy

/*
	自己写编写函数实现strcpy的功能
*/

//char *strcpy(char *dest, const char *src)

#include <stdio.h>

char *My_strcpy(char *dest,char *src)
{
	if(dest == NULL || src ==NULL)
	{
		return NULL;
	}
	
	char *back = dest;			//定义一个备份来存放dest的地址,因为dest会偏移
	
	while(*src != '\0')
	{
		*dest = *src;
		dest++;
		src++;
	}
	*dest = '\0';				//字符串结束标志
	
	return back;
}

char *My_strcpy2(char *dest,char *src)
{
	if(dest == NULL || src == NULL)
	{
		return NULL;			//只要目标函数或者源有一个是空指针的话,就不做拷贝,返回空指针
	}
	
	char *back = dest;
	
	while(*src != '\0')
	{
		*dest++ = *src++;		//先将src中的值取出来后偏移,赋值给dest后偏移
	}
	*dest = '\0';
	
	return back;
}

char *My_strcpy3(char *dest,char *src)
{
	if(dest == NULL || src == NULL)
	{
		return NULL;
	}
	
	char *back = dest;
	
	while((*dest++ = *src++) != '\0');		//while中的判断条件不仅有0或1,下边有举例
	*dest = '\0';
	
	return 0;
}

int main()
{
	char *p = "makabaka";
	char str[128] = {'\0'};
	
	/*char a = 'm';
	char b;
	if((b = a) == 'm')				if或者while中的判断条件不单只有0和1
	{
		printf("条件成立\n");
	}*/
	
	My_strcpy3(str,p);
	
	puts(str);
	
	return 0;
}

/*
	自己写编写函数实现strncpy的功能
*/

//char *strncpy(char *dest, const char *src, size_t n)


#include <stdio.h>

char *My_strncpy(char *dest,char *src,int count)
{
	if(dest ==NULL || src == NULL)
	{
		return NULL;
	}
	
	char *back = dest;
	
	while(*src != '\0' && count > 0)
	{
		*dest++ = *src++;
		count--;
	}
	if(count > 0)
	{
		while(count>0)
		{
			count--;
			*dest++ = '\0';
		}
		return dest;
	}
	*dest = '\0';
	
	return back;
}

int main()
{
	char *p = "makabaka";
	char str[128] = {'\0'};
	
	My_strncpy(str,p,6);		//指定从p中拷贝多少字符到str中
	
	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>		

char *My_strcpy(char *dest,char *src)
{
	assert(dest != NULL && src != NULL);
	
	/*if(dest == NULL || src == NULL)
	{									之前的判断方法
		return NULL;
	}*/
	
	char *back = dest;
	
	while((*dest++ = *src++) != '\0');
	*dest = '\0';
	
	return back;
}

int main()
{
	char *p = "makabaka";
	//char *p = NULL;		只要目标函数和源有一个位空指针,就会调用assert中的abort来终止程序运行
	char str[128] = {'\0'};
	
	My_strcpy(str,p);
	
	puts(str);
	
	return 0;
}

 字符串拼接

 编程说明:字符串拼接 strcat

/*
	用strcat实现字符串的拼接
*/


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

int main()
{
	char str[] = "maka";
	char *p = "baka";
	
	strcat(str,p);
	
	puts(str);
	
	return 0;
}

 编程说明:自己编写函数实现strcat的函数功能

/*
	用strcat实现字符串的拼接
*/

//char *strcat(char *dest, const char *src)


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

char *My_strcat(char *dest,char *src)
{
	assert(dest != NULL && src != NULL);
	
	char *back = dest;
	
	while(*dest != '\0')
	{
		dest++;
	}
	while((*dest++ = *src++) != '\0');
	*dest = '\0';
	
	return back;
}

char *My_strcat2(char *dest,char *src)
{
	assert(dest != NULL && src != NULL);
	
	char *back = dest;
	strcpy(dest+strlen(dest),src);
	
	return back;
}

char *My_strcat3(char *dest,char *src)
{
	assert(dest != NULL && src != NULL);
	
	char *back = dest;
	
	for(;*dest != '\0';dest++);
	while((*dest++ = *src++) != '\0');
	
	return back;
}

int main()
{
	char str[] = "maka ";
	char *p = "baka !";
	
	My_strcat3(str,p);
	
	puts(str);
	
	return 0;
}

 字符串比较

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

/*
	strcmp的功能:比较字符串的大小
*/

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


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

int main()
{
	char *p1 = "Welcome";	
	char *p2 = "welcome";
	/*
		若p1 = p2,则返回值n = 0;
		若p1 > p2,则返回值n = 1;	(根据ASCII码的大小)
		若p1 < p2,则返回值n = -1;
	*/
	
	int n = strcmp(p1,p2);
	
	printf("n = %d\n",n);
	
	return 0;
}

/*
	strncmp的功能:比较指定字符串的大小
*/

//int strncmp ( const char * str1, const char * str2, size_t n )


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

int main()
{
	char *p1 = "makabakakakak";
	char *p2=  "makabakalllll";
	
	/*
		功能是把 str1 和 str2 进行比较,最多比较前 n 个字节,
		若str1与str2的前n个字符相同,则返回0;
		若s1大于s2,则返回大于0的值;
		若s1 小于s2,则返回小于0的值。
	*/
	
	int n = strncmp(p1,p2,7);	//指定比较前7位的字符串大小
	
	printf("n = %d\n",n);
	
	
	return 0;
}

  由此可见:strcmp 和 strncmp 的区别是strncmp可以指定要比较前多少个字符,strcmp只可以比较全部字符大小,两个都是最终返回0,1, -1。

查找子字符

C 库函数 - strchr()

描述

C 库函数 char *strchr(const char *str, int c) 在参数 str 所指向的字符串中搜索第一次出现字符 c(一个无符号字符)的位置。

声明

char *strchr (const char *str, int c)

参数

  • str -- 要被检索的 C 字符串。
  • c -- 在 str 中要搜索的字符。

返回值

该函数返回在字符串 str 中第一次出现字符 c 的位置,如果未找到该字符则返回 NULL。

 编程说明:查找子字符 : strchr

/*
	strchr的功能:查找子字符:
*/

//char *strchr(const char *str, int c)


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

int main()
{
	char str[] = "maka-baka";
	char ch = '-';
	
	char *ret;
	
	ret = strchr(str,ch);
	
	if(ret)				//如果找到字符ch,则输出Found,否则输出Not Found
	{
		puts("Found");
	}
	else
	{
		puts("Not Found");
	}
	
	printf(" |%c| 后的字符是:|%s|\n",ch,ret);
	
	return 0;
}

查找子字符串

C 库函数 - strstr()

描述

C 库函数 char *strstr(const char *haystack, const char *needle) 在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 '\0'。

声明

char *strstr (const char *haystack , const char *needle)

参数

  • haystack -- 要被检索的 C 字符串。
  • needle -- 在 haystack 字符串内要搜索的小字符串。

返回值

该函数返回在 haystack 中第一次出现 needle 字符串的位置,如果未找到则返回 null。

 编程说明:查找子字符串:strstr

/*
	strstr的功能:查找子字符串
*/

//char *strstr(const char *haystack, const char *needle)

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

int main()
{
	char str[] = "makabaka";
	char de[] = "baka";
	
	char *ret;
	
	ret = strstr(str,de);
	
	if(ret)
	{
		puts("Found");
	}
	else
	{
		puts("Not Found");
	}
	
	printf("子字符串是:|%s|",ret);
	
	return 0;
}

 字符串分割

C 库函数 - strtok()

描述

C 库函数 char *strtok(char *str, const char *delim) 分解字符串 str 为一组字符串,delim 为分隔符。如果传入字符串,则传入的字符串中每个字符均为分割符)。首次调用时,str指向要分解的字符串,之后再次调用要把str设成NULL

声明

char *strtok (char *str , const char *delim)

参数

  • str -- 要被分解成一组小字符串的字符串。
  • delim -- 包含分隔符的 C 字符串。

说明:

       当strtok()在参数str的字符串中发现参数delim中包含的分割字符时,则会将该字符改为\0 字符。在第一次调用时,strtok()必需给予参数str字符串,往后的调用则将参数str设置成NULL。每次调用成功则返回指向被分割出片段的指针。

返回值

该函数返回被分解的第一个子字符串,如果没有可检索的字符串,则返回一个空指针。

 编程说明:字符串分割:strtok

/*
	strtok的功能:分割字符串
*/

//char *strtok(char *str, const char *delim)


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

int main()
{
	char str[] = "ma.ka.ba.ka";
	char de[] = ".";
	
	char *tok;
	
	tok = strtok(str,de);
	
	while(tok != NULL)
	{
		printf("分割后的字符是:|%s|\n",tok);
		
		tok = strtok(NULL,de);
	}
	
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

日落星野

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值