五大板块(3)——字符串

一、字符串的定义方式与输出

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

int main()
{
        int i;

        //定义方式一
        char str1[3] = {'a','b','c'};

        //定义方式二
        char str2[3] = "abc";

        //定义方式三
        char str3[] = "chen li chen mei wo shuai";

        //输出方式一:for循环拼接多个字符
        for(i=0;i<sizeof(str3)/sizeof(str3[0]);i++){
                printf("%c",str3[i]);
        }

        //输出方式二:
        printf("%s\n",str3);

        //输出方式三:调用字符串API
        puts(str3);

        return 0;
}

结果:

chen li chen mei wo shuaichen li chen mei wo shuai
chen li chen mei wo shuai

其中第三种定义方式 char str3[] = “str”; 不指明数组的大小,只给出了数组名,而数组名的值是个指针常量,也就是数组第一个元素的地址。

是不是可以猜想,首地址就是字符串的关键呢?

而指针也指明了地址,故可以用指针的方式定义字符串,即字符串指针。也是定义字符串的常用方式。

char* name = "huatianzhu";

注意: 这里说的定义是同时赋值,而不是等待赋值。之所以不需要给指针name分配空间,是因为进行了初始化,编译的时候系统就知道需要分配多大的空间,否则要开辟空间。(后文中也有涉及)。

二、字符串的结尾是 ’ \0 ’

字符串都是以类似于下面的方式输出:遇到 ‘\0’
#include <stdio.h>
        
int main()
{
        int i;
        char str[] = "abcd";
               
        while(str[i] != '\0'){
                printf("%c",str[i]);
                i++;
        }
        
        return 0;
}

所以用strlen计算有效字符的长度
在很多场景,我们都需要在程序的执行过程中录入字符串,如下:

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

int main()
{
        char name[128];//系统预分配空间

        printf("请输入名字\n");
        scanf("%s",name);//才能进行赋值

        printf("sizeof计算:%d\n",sizeof(name)/sizeof(name[0]));
        printf("strlen计算:%d\n",strlen(name));

        return 0;
}

运行结果:

请输入名字
huatianzhu
sizeof计算:128
strlen计算:10

实际上huatianzhu长这样:

huatianzhu\0\0\0\0.....

strlen当遇到\0时便停止计算,是专门用来计算字符串的长度。

这时候你好奇了,输入中文字符,用strlen计算是多少?

输入:

钱钱钱

可以发现结果是 9.这与linux系统采用utf-8的编码方式相关,一个汉字占用3个字节。

strlen使用(1)注意字符数组当做字符串来用?

有一个说法是:把字符数组当做字符串来使用时,最后一个元素要是’\0’,否则strlen()计算时就会发生“停不下来”,直到遇到内存的’\0’,故计算出来就不会是一个准确的值。例如:

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

int main()
{
        char array[5] = {'a','b','c','d','e'};
        printf("%d\n",strlen(array));

        return 0 ;
}

可我放在树莓派上运行,结果都是5。而在啊哈C中,都是6。

三、字符串操作常用API

1、puts、gets —— 输入与输出
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main()
{
        char* str = (char *)malloc(128);//直接赋值NULL不行,必须malloc开辟空间  有笔有纸才能写
        if(str == NULL){
                printf("malloc error\0");//malloc开辟空间可能会失败 同时注意内存泄漏
                exit(-1);
        }
        memset(str,'\0',128);
        printf("请输入任意字符串\n");
        gets(str);
        puts(str);//内置了一个\n

        return 0;
}

结果:

请输入任意字符串
chenlichen
chenlichen

不安全的gets

警告:

warning: the `gets' function is dangerous and should not be used.

用这个就可以:

fgets(str,128,stdin);//128为size

对比get和fgets

fgets从stdin中读字符,直至读到换行符或文件结束,但一次最多读size个字符。读出的字符连同换行符存入缓冲区str中。返回指向str的指针。

而gets把从stdin中输入的一行信息存入cmd中,然后将换行符置换成串结尾符NULL。用户要保证缓冲区的长度大于或等于最大的行长。

注意gets的行为与fgets使用stdin作为参数时的行为不完全一样:首先,gets不包含结束的换行符,而fgets包含。其次,gets不允许指定要读取的字符数量的限制,因此必须小心str所指向的数组的大小,以避免缓冲区溢出。

strcpy、strncpy —— 拷贝

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

把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间

char *strncpy(char *destinin, char *source, int maxlen);

把src所指向的字符串中以src地址开始的前maxlen个字节复制到dest所指的数组中,并返回被复制后的dest

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

int main()
{
        char* strDes = (char*)malloc(128);//不开辟空间就是野指针 会出现断错误
        memset(strDes,'\0',128);
        char* strSrc = "clc mws";
        
        puts(strcpy(strDes,strSrc));
        
        memset(strDes,'\0',128);

        strncpy(strDes,strSrc,3);
        puts(strDes);

        return 0;
}

结果:

clc mws
clc

strcmp —— 比较

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

当s1<s2时,返回为负数;
当s1=s2时,返回值= 0;
当s1>s2时,返回正数。

示范:

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

int main()
{       
        char str1[128]={'\0'};
        char str2[128]={'\0'};//最快的开辟字符串空间并初始化

        puts("请输入字符串1");  
        fgets(str1,128,stdin); //stdin标准输入
        puts("请输入字符串2");
        fgets(str2,128,stdin);
                
        if(strcmp(str1,str2) == 0){
                printf("一样\n");
        }
        else{
                printf("不一样\n");
        }

        return 0;
}

strchr、strstr —— 检索

char *strstr(const char *haystack, const char *needle)
在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 ‘\0’,并且返回第一次出现字符串 needle (strchr检索的是字符)的位置,注意了,是返回第一次出现的位置,不是返回字符串needle,很多人有这个误解

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

int main()
{
        char haystack[32] = "chenlichen mei wo shuai";
        char needle[32] = {'\0'};
        char* ret = NULL;
        //ret = (char* )malloc(32);//如果不在while中malloc,将会段错误
                                   //ret的值是变化的,要一直动态分配空间

        while(1){

                ret =(char* )malloc(32);
                memset(ret,'\0',32);

                memset(needle,'\0',32);//而这个字符数组只需要擦除原有数据

                printf("现有字符串:%s,请输入需要检索的字段\n",haystack);

                //fgets(needle,32,stdin);//不明白为啥用这个一个no find
                //printf("%s\n",needle);//明明这里也可以输出正常
                scanf("%s",needle);
                ret = strstr(haystack,needle);//这里的赋值决定了ret只能被定义为字符指针,而不是数组。
                
                if(ret != NULL){
                        printf("子字符串是:%s\n",ret);
                }
                else{
                        puts("no find");
                }
        }
        return(0);
}

运行结果:

现有字符串:chenlichen mei wo shuai,请输入需要检索的字段
chen
子字符串是:chenlichen mei wo shuai

现有字符串:chenlichen mei wo shuai,请输入需要检索的字段
wo
子字符串是:wo shuai

现有字符串:chenlichen mei wo shuai,请输入需要检索的字段
shuai
子字符串是:shuai


strlwr、strupr —— 大小写转换
#include <stdio.h>

char* strlwr(char *str)
{
        if(str == NULL)
                return NULL;
		char *p = str;
        while (*p != '\0'){
                if(*p >= 'A' && *p <= 'Z')
                        *p = (*p) + 0x20;//大小写差32
                p++;
        }
        return str;
}


char* strupr(char *str)
{
        if(str == NULL)
                return NULL;
		char *p = str;
        while (*p != '\0'){
                if(*p >= 'a' && *p <= 'z')
                        *p = (*p) - 0x20;
                p++;
        }
        return str;
}

int main()
{
        char str[128] = {'\0'};
        printf("请输入字符串\n");
        fgets(str,128,stdin);
        printf("转换为小写:%s\n",strlwr(str));
        printf("转换为大写:%s\n",strupr(str));
        return 0;
}

strcat —— 拼接

extern char *strcat(char *dest, const char *src);

把src所指向的字符串(包括“\0”)复制到dest所指向的字符串后面(删除*dest原来末尾的“\0”),*src中原有的字符不变。返回指向dest的指针。

要保证dest足够长,以容纳被复制进来的src。

示范:

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

int main()
{
        char str1[32] = "chenlichen";
        char str2[] = "meiwoshuai";

        //拼接后放在str1,所以str1的长度在定义的时候必须指明并且足够大
        puts(strcat(str1,str2));

        return 0;
}

strtok —— 分割(作为重点介绍)
#include <stdio.h>
#include <string.h>

int main(void)
{
        char s[] = "aaa bbb ccc ddd";
        char c[] = " ";

        char *r = strtok(s, c);

        while (r != NULL) {
                printf("%s\n", r);
                r = strtok(NULL, c);//获取下一个串的方式比较奇葩,目标字符串改为NULL
        }

        return 0;
}

输出结果:

aaa
bbb
ccc
ddd

demo2:

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

void main()
{

	//字符串分割:strtok—头文件: #include <string. h>
	//函数原型: char *strtok(char* str,const char* delimiters);
	//参数: str: 待分割的字符串(c-string) ; delimiters: 分割符字符串。
    char* p = (char*)malloc(128);
    memset(p,'\0',128);
    //char* p = NULL;  这样也可以 防止野指针
    
	//char* str2 = "ni,hao,zhe,ge,shi,jie"; 这种方法不可以!!
    char str2[] = "ni,hao,zhe,ge,shi,jie";
	p = strtok(str2,",");
	if (p == NULL) {
		printf("无法分割");
	}
	
    else puts(p);
    //else printf("%s",p); 两中输出方式都可以 此种输出效率更高
	puts(strtok(NULL,","));//获取下一个串的方式比较奇葩,目标字符串改为NULL
    puts(strtok(NULL,","));//获取下一个串的方式比较奇葩,目标字符串改为NULL
    puts(strtok(NULL,","));//获取下一个串的方式比较奇葩,目标字符串改为NULL
	puts(strtok(NULL,","));//获取下一个串的方式比较奇葩,目标字符串改为NULL
   
    
    system("pause");

}   

sprintf —— 最常用的带格式字符串拼接函数
#include <stdio.h>
#include <string.h>

int main(){

        char s[64];
        char* who = "I";
        char* whom = "CSDN";
        sprintf(s, "%s love %s.", who, whom); //产生:"I love CSDN. " 这字符串写到s中
        puts(s);
        sprintf(s, "%10.3f", 3.1415626); //产生:" 3.142"
        puts(s);
}

四、自己实现这些API

1.puts
#include <stdio.h>

void myputs(char *p)
{
        while(*p!='\0'){
			printf("%c",*p);
			p++;
		}
}

int main()
{
        char* str ="adsjadsnadsknadsk";
        myputs(str);
        return 0;
}

2.gets
#include <stdio.h>
#include <stdlib.h>

void mygets(char *p)
{
        if(p == NULL){
                exit(-1);
        }
        while(*p = getchar()){
                if(*p == '\n'){
                        return;//用break也可以
                }else{
                        p++;
                }
        }
}
int main()
{
        char str[128] = {'\0'};
        printf("请输入字符串:\n");
        mygets(str);
        puts(str);
        return 0;
}

3.mystrlen
#include <stdio.h>
#include <stdlib.h>
int mystrlen(char* p)
{
	int cnt = 0;
	while(p!='\0'){
		cnt++;
		p++;
	}
	return cnt;
}
int main()
{
	char* str = "adsasfadas";
	printf("str的长度为:%d\n",mystrlen(str));
	return 0;
}
4.mymemset
#include <stdio.h>
#include <stdlib.h>
void mymemset(char* p,char c,int size)
{
	while(size){
		*p = c;
		 p++;
		 size--;	
	}
}
int main()
{
	 char *str = NULL;
     str = (char *)malloc(128);
     mymemset(str,'\0',128);
     puts(str);
	 return 0;
}
5.mystrcpy
#include <stdio.h>
#include <stdlib.h>
char * mystrcpy(char dest[],char *src)
{
        if(dest == NULL || src == NULL){
                return NULL;
        }
        while(*src != '\0'){
                *dest++ = *src++;
        }
        *dest = '\0';
        return dest;//返回的是数组的首地址 指针的话要注意回调
}

int main()
{
        char dest[128] ={'\0'};
        char *src ="this is a mystrcpy test";
        mystrcpy(dest,src);
        puts(dest);
        return 0;
}

6.strcmp
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

int mystrcmp(char* p1,char* p2)
{
	assert(p1);
	assert(p2);
	while(*p1 == *p2){
		if(*str1 == '\0') {
              return 0;
        }
		p1++;
		p2++;
	}
	return *str1-*str2;
}
int main()
{
	char *str1="hello";
    char *str2="hello";
    int ret = mystrcmp(str1,str2);
    if(ret == 0){
		printf("倆字符串相等\n");
    }else if(ret > 0){
		printf("字符串一比字符串二大\n");
    }else{
		printf("字符串一比字符串二小\n");
    }
	return 0;
}
7.mystrcat
#include <stdio.h>
#include <stdlib.h>
char * mystrcat(char dest[],char *src)
{
        while(*dest!='\0'){//遍历到尾巴
                dest++;
        }
        while(*src != '\0'){
                *dest++ = *src++;
        }
        *dest = '\0';

        return dest;
}

int main()
{
        char dest[128] ="hello ";

        char *src ="this is a mystrcat test";

        mystrcat(dest,src);

        puts(dest);



        return 0;
}

8.字母大小写的转换
#include<stdio.h>
 
void main()
{
	char a;          
	printf("请输入一个字母:");
	scanf("%c",&a);
 
	if(a <= 91)         //对应ASCII表判断输入字母的ASCII值,大写字母A~Z的ASCII值为65~91
	{
		a = a +32;   //字母a~z的ASCII值为97~123,则给该字符加32之后,他的ASCII值变为对应的小写字母的ASCII值
		printf("该子母的小写形式为:%c\n",a);
 
	}
	else
	{
		a = a-32;   //同大写变小写的ASCII值的转换
		printf("该子母的大写形式为:%c\n",a);
	}
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值