为了成功上岸之字符串代码总结

整数转字符串(不用itoa)

char* itoa(int value,char*string,int radix);
value: 要转换的整数,string: 转换后的字符串,radix: 转换进制数,如2,8,10,16
0(数字零)的ASCII码是48;A的ASCII码是65;a的ASCII码是97;
负号要考虑

#include<stdio.h>

char *My_Int2String(int num, char *str);

int main()
{
	int number1 = 123456;
	int number2 = -123456;
	char strings[16] = {0};
	
	My_Int2String(number1, strings);
	printf("数字:%d 转换后的字符串为:%s\n", number1, strings);
	My_Int2String(number2, strings);
	printf("数字:%d 转换后的字符串为:%s\n", number2, strings);

	return 0;
}

char *My_Int2String(int num, char *str)
{
	int i = 0;
	if(num < 0)      //判断是否为负整数,需要先将负号提出 
	{
		num = -num;
		str[i++] = '-';
	}
	
	do
	{
		str[i++] = num % 10 + 48;      //0的ASCII为48 
		num = num / 10;      //求余法将整数一位一位转化 
	} while(num);
	
	str[i] = '\0';      //一定要加这个!!!因为是字符串!!!!!!!!!! 
	
	i--;
	int j = 0;
	char c;
	if('-' == str[0] )
		j = 1;
	while( i > j)      //转化后顺序倒了,调整 
	{
		c = str[i];
		str[i] = str[j];
		str[j] = c; 
		j++;
		i--; 
	}
	
	return str;
}

在这里插入图片描述

字符串转整数(不用atoi)

int atoi(const char *nptr);
字符串转整数函数,nptr: 要转换的字符串
字符串转化成整数,可以采用减‘0’再乘10累加的办法,字符串减‘0’就会隐形转化成int类型

#include<stdio.h>

int My_String2Int(char *str);

int main()
{
	printf("字符串\"123456\"转换为数字:%d\n", My_String2Int("123456"));

	printf("字符串\"-123456\"转换为数字:%d\n", My_String2Int("-123456"));

	return 0;
}

int My_String2Int(char *str)
{
	char flag = '+';      //符号标志位
	long num = 0;
	
	if(*str == '-')
	{
		flag = '-';
		str++;	
	} 
	
	while(*str >= '0' && *str <= '9')
	{
		num = 10*num + (*str - '0');
		str++;
	}
	 
	if(flag == '-')      //处理是负数的情况
	{
		num = -num;
	}

	return (int)num;
}

在这里插入图片描述

字符串中有多少个单词

规定:
单词的个数由空格出现的次数决定,连续的空格作为出现一次空格,一行开头的空格不统计在内。 如果测出某一字符为非空格,而它的前面的字符是空格,则表示“新的单词开始了”,此时使单词数count累加1。 如果当前字符为非空格,而其前面的字符也是非空格,则意味着仍然是原来那个单词的继续,count不应再累加1。 添加一个标志word,用来标识当前字符的前一个字符是否为空格;若word等于0,则表示前一个字符是空格;若word等于1,则表示前一个字符为非空格。

#include<stdio.h>

#define BUFFERSIZE 1024

int main()
{
	char string[BUFFERSIZE];
	gets(string);
	
	int i;
	char c;
	int count =0;
	int word = 0;      //用于判断是否为“空格+字符”的情况
	for(i =0; (c = string[i]) != '\0'; i++)
	{
		if(c == ' ')
			word = 0;      //不能一遇到空格就加一 
		else if(word == 0)
		{
			word = 1;
			count++;
		}
	}
	printf("一共有 %d 个单词\n", count);
	
	return 0; 
}

在这里插入图片描述

字符串的逆序(反转)

在ANSI C中,初始化指针时所创建的字符串常量被定义为只读。与指针相反,由字符串常量初始化的数组是可以修改的。
方法一:使用了一个临时变量来实现,字符串首尾换位置即可:

#include<stdio.h>

char *My_Reserve_String(char *str);

int main()
{
	char str[] = "abcdefgh";      //为什么用char *str = "abcdefgh"不行,上面写了
	printf("字符串 %s ", str);
	printf("翻转之后为 %s\n", My_Reserve_String(str)); 
	
	return 0;
}

char *My_Reserve_String(char *str)
{
	char *p = str;      //p指向字符串头 
	int len = 0;
	char *c = str;
	for(; *c != '\0'; c++)      //c用于计算字符串长度 
		len++;
	char *q = p + len - 1;      //q指向字符串尾
	
	char t;
	while(q > p)
	{
		t = *p;
		*p++ = *q;
		*q-- = t;	
	} 
	
	return str;
}

在这里插入图片描述
方法二:直接交换,不使用了一个临时变量,不过要用到知识:
假设要交换两个变量a, b,则可以使用按位异或的方法,此法效率最高:
a = a^b; b = a^b; a = a^b

#include<stdio.h>

char *My_Reserve_String(char *str);

int main()
{
	char str[] = "abcdefgh";
	printf("字符串 %s ", str);
	printf("翻转之后为 %s\n", My_Reserve_String(str)); 
	
	return 0;
}

char *My_Reserve_String(char *str)
{
	char *p = str;      //p指向字符串头 
	int len = 0;
	char *c = str;
	for(; *c != '\0'; c++)      //c用于计算字符串长度 
		len++;
	char *q = p + len - 1;      //q指向字符串尾
	
	while(q > p)
	{
		*p = *p ^ *q;
		*q = *p ^ *q;
		*p = *p ^ *q;	
		p++;
		q--;
	} 
	
	return str;
}

在这里插入图片描述

一个句子中单词的逆序(反转)

方法一

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

void reverse_str(char *ch, int front, int end)      //用异或直接交换字符串反转 
{
	while(front < end)
	{
		ch[front] = ch[front] ^ ch[end];
		ch[end] = ch[front] ^ ch[end];
		ch[front] = ch[front] ^ ch[end];
		front++;
		end--;
	}
}

void SwapWord(char *str)
{
	int len = strlen(str);
	reverse_str(str, 0, len-1);      //先把所有字符一起反转了 
	
	int begin = 0;
	int i;
	for(i = 0; i < len; i++)      //再把单个单词反转 
	{
		if(str[i] == ' ')
		{
			reverse_str(str, begin, i-1);
			begin = i + 1;
		}
	}
	reverse_str(str, begin, len-1);      //最后一个单词的反转 
}

int main()
{
	char str[] = "how are you";
	printf("字符串 %s 反转后为:", str);
	SwapWord(str);
	printf("%s\n", str);
} 

在这里插入图片描述
方法二:

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

void reverse(char *s, int begin, int end)
{
	char temp;
	while(end > begin) 
	{
		temp = s[begin];
		s[begin] = s[end];
		s[end] = temp;
		begin++;
		end--;
	}
}

int main()
{
	int a, b;
	a = b = 0;
	char s[100];
	gets(s);
	reverse(s, 0, strlen(s)-1);
	int i = 0;
	while(i < strlen(s)) {
		//跳过空格 
		while(s[i] == ' ' && i < strlen(s)) {
			i++;
		}
		a = i;
		//跳过非空格字符 
		while(s[i] != ' ' && i < strlen(s)) {
			i++;
		}
		b = i-1;
		//a~b为一个单词的下标的区间 
		reverse(s,a, b);
	}
	puts(s);
	return 0;
}

在这里插入图片描述

从字符串中“aecbcda”找出不重复的字符组成的顺序子串“aecbd”,用最优的时空复杂度。

很简单:就是搜索一遍,有的话放到另一个数组`

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

int main()
{
	char a[100], b[100];
	int i, j, len, flag, count = 0;
	gets(a);
	len = strlen(a);
	for(i = 0; i < len; i++)      //一个一个字母往后去,去排查前面的有没有重复 
	{
		flag = 1;      //没有重复就去往新的数组里加数 
		for(j = i - 1; j >= 0; j--)
			if(a[i] == a[j])
			{
				flag = 0;
				break;
			 } 
		if(flag == 1)
			b[count++] = a[i];
	}
	b[count] = '\0';
	puts(b);
}

在这里插入图片描述

字符串中第一个只出现一次的字符

用到了hash,一个字符对应一个位置,所以要申请256个空间。(unsigned char)强转是因为char类型符号一般为有符号的,若出现负值就越界了,还要注意字符串中‘\0’的值在ASCII中为0;

#include<stdio.h>

#define SIZE 256      //因为ASCII有256个字符

char Get_Char(char *str)
{
	if(!str)      //传入字符串为空 
		return 0;
		
	char *p = NULL;
	unsigned char count[SIZE] = {0};
	char buffer[SIZE];
	char *q = buffer;
	
	//此为hash表,count表和buffer表一一对应 
	for(p = str; *p != 0; p++)      //p不为零是不是就是说不到最后,因为是字符,所以0和‘0’不同 
		if(++count[(unsigned char)*p] == 1)      //判断是否为第一次出现的字符,并在count中计数 
			*(q++) = *p;      //若第一次出现则在q中记录下来是什么字符
		
			
	for(p = buffer; p < q; p++)
		if(count[(unsigned char)*p] == 1)      //在计数表中找到第一个出现 
			return *p;
	
	return 0; 	 
}

int main()
{
	printf("%c\n", Get_Char("zbzc"));
	
	return 0;
} 


字符串所有组合(排列组合)

用此针对不同且不减少字符的:使用的是递归法
在这里插入图片描述

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

void swap(char *p1, char *p2 )
{
	char tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

//str为待排序的字符串,pStart为待排序的子字符串 
void Permutation(char *str, char *pstart)
{
	if(str == NULL || pstart ==NULL) 
		return;
	//完成全排列后输出当前排列的字符串
	if(*pstart == '\0')
		printf("%s\n", str);
	else
	{
		char *p;
		for(p = pstart; *p != '\0'; p++)
		{	
			swap(pstart, p);      //交换第一个字符pstart和遍历到的字符p 
			Permutation(str, pstart+1);      //固定第一个字符,对剩下的字符进行全排列 
			swap(pstart, p);      //还原刚才交换的两个字符,方便遍历所有元素后进行 
		}				
	} 	
}
 
int main()
{
	char str[] = "abcd";
	Permutation(str, str);
	return 0;
}

在这里插入图片描述

字符串所有组合(排列组合)

用此针对有相同且不减少字符的:
由于有相同的字母,而且用的是交换字母的方式,所以在全排列时会出现abb的情况。所以需要:从第一个字符起,每个字符分别与他之后的非重复出现的字符进行交换。在递归的方法基础上,只需要增加一个判断字符是否重复的函数即可:这个函数来判断在之前是否已经出现了相同的字符,出现的话就没必要再去交换排列了

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>      //bool类型头文件要加进去 

void swap(char *p1, char *p2 )
{
	char tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

//判断在[begin,end)区间内是否有与end相同的字符 ,没有返回ture 
bool IsDuplicate(char *begin, char *end)
{
	char *p;
	for(p = begin; p < end; p++)
		if(*p == *end)
			return false;
	
	return true; 
}

//str为待排序的字符串,pStart为待排序的子字符串 
void Permutation(char *str, char *pstart)
{
	if(str == NULL || pstart ==NULL) 
		return;
	//完成全排列后输出当前排列的字符串
	if(*pstart == '\0')
		printf("%s\n", str);
	else
	{
		char *p;
		for(p = pstart; *p != '\0'; p++)
		{	
			if(!IsDuplicate(pstart, p))
				continue;      //只跳出本次循环 
			swap(pstart, p);      //交换第一个字符pstart和遍历到的字符p 
			Permutation(str, pstart+1);      //固定第一个字符,对剩下的字符进行全排列 
			swap(pstart, p);      //还原刚才交换的两个字符,方便遍历所有元素后进行 
		}				
	} 	
}
 
int main()
{
	char str[] = "acad";
	Permutation(str, str);
	return 0;
}

在这里插入图片描述

字符串所有组合(排列组合)

此为有序的:a b c d ab ac ad abc bcd abcd

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

/*
 * str      : 输入的字符串
 * output   : 临时保存一个输出
 * num      : 当前一个输出总共有多少位
 * start    : 当前以那个位置上的字符起头的
 * cur      : 当前输出的是哪一位
 * index    : 当前输出的是位的迭代器
 * 输入:  abcd
 * 输出:a b c d ab ac ad abc bcd abcd
 */
void recursion(char * str,char * output,int num,int start,int cur,int index){
    int len = (int)strlen(str);
    if (num == cur) {
        // 取最后一位
        if (index < len) {
            output[cur-1] = str[index];
            printf("%s ",output);
            recursion(str,output,num,start,cur,index+1);
        }
    }else{
        // 遍历取以start起头的第cur位的值
        // 这个值的范围是 [start + cur - 1 ~ len]
        int i;
        for (i = start + cur - 1; i < len; i++){
            output[cur-1] = str[i];
            // 递归取第cur位的值
            recursion(str,output,num,start,cur+1,i+1);
            // 取完所有的cur位后,把起头位置start往后移一位
            start++;;
        }
    }
}
void recurs(char * str){
    char output[128] = {0};
    int len = (int)strlen(str);
    int i;
    for (i = 1; i <= len ; i++) {
        memset(output, 0, 128);
        recursion(str,output,i,0,1,0);
        printf("\n");
    }
}
int main() {
    char * str = "abcd";
    recurs(str);
    return 0;
}


在这里插入图片描述

此为无序的:

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

int Recursion(char *str,char *s, int len,int m,int n){
    int i,j;
    int flag;
    for(i = n; i < len; i++){
        if(i > n){//当i>n说明,递归结束
            m--;
        }
        s[m] = str[i];
        s[++m] = '\0';
        printf("%s ",s);
        if(i < len-1)
            Recursion(str, s, len,m,i+1);
    }
}

int main(void){
    int len,i,j,m;
    char s[6]={0};
    char *str = "12345";
    len = strlen(str);
    Recursion(str,s,len,0,0);
}

在这里插入图片描述

查找字符串中每个字符出现的个数

用一个数组为256个元素的来记录就行了

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

#define MAX 256

int main()
{
	int count[MAX] = {0};
	int i;
	char str[MAX];
	gets(str);
	
	for(i = 0; i< strlen(str); i++)
		count[str[i]]++;
	
	for(i = 0; i < 256; i++)
		if(count[i] > 0)
			printf("%c 有 %d 个\n", i, count[i]);
	
	return 0;
}

在这里插入图片描述

自己实现memcpy /memmove(并且增加了memcpy 的内存重叠性)

函数原型是void *memcpy(void *dest, const void *scr, size_t n);
还有疑问:size_t和int的区别,为什么换成size_t不行了

#include <stdio.h>

void *MyMemcpy(void *dest, const void *src, int num)      //num是多少个字节 
{
	//先判断src额dest是否为空指针 
	if(dest == NULL || src == NULL)
		return NULL;
	//在实现的时候,需要把void*转换成能进行操作的数据类型,如char*
	char *pdest = (char *)(dest);
	const char *psrc  = (char *)(src);
	int i;
	
	//dest和src有重叠且dest指向src中的元素,因此需要对src从后向前复制
	if(pdest > psrc && pdest < psrc + num)      //可以不等于 psrc + num
		for(i = num - 1; i > -1; i--)
			pdest[i] = psrc[i];
			
	//src指向dest中的元素或没有重叠(普通情况),因此需要对src从前向后复制 
	else
		for(i = 0; i < num; i++)
			pdest[i] = psrc[i];
			
	return dest;
}

int main()
{
	char src[] = "abc";
	char *dest = (src + 1);      //第一种情况
	dest = (char *)MyMemcpy(dest, src, 4);      //要强转成需要的操作类型 
	printf("%s\n", dest);
	
	return 0;
}

在这里插入图片描述

自己实现strcpy(不考虑重叠)

函数原型是char *strcpy(char *dest, const char *scr);
返回指向dest的指针,注意!!!是把包括到‘\0’结束的字符串都复制过去,所以空间必须够,防止数组越界。
如果要考虑有重叠的情况,要用上面memcpy来实现。注意用memcpy的参数时num的值必须加1(保证‘\0’也被复制)

assert的意义:对于断言,相信大家都不陌生,大多数编程语言也都有断言这一特性。简单地讲,断言就是对某种假设条件进行检查。在 C 语言中,断言被定义为宏的形式(assert(expression)),而不是函数,其原型定义在<assert.h>文件中。其中,assert 将通过检查表达式 expression 的值来决定是否需要终止执行程序。也就是说,如果表达式 expression 的值为假(即为 0),那么它将首先向标准错误流 stderr 打印一条出错信息,然后再通过调用 abort 函数终止程序运行;否则,assert 无任何作用。

char *strcpy(char *strDest, const char *strSrc)
{
	assert((strDest != NULL) && (strSrc != NULL));
	if(strDest == strSrc)
		return strDest;
	char *address = strDest;
	while((*strDest++ = *strSrc++) != '\0');
	
	return address;
}

strstr函数

函数原型是char *memcpy(char *str1, char *str2);
用于判断字符串2是否为字符串1的字串。是的话返回str2在str1中首次出现的首地址;否则返回NULL。

自己实现memcpy /memmove(并且增加了memcpy 的内存重叠性)

函数原型是void *memcpy(void *dest, const void *scr, size_t n);
还有疑问:size_t和int的区别,为什么换成size_t不行了

#include <stdio.h>

void *MyMemcpy(void *dest, const void *src, int num)      //num是多少个字节 
{
	//先判断src额dest是否为空指针 
	if(dest == NULL || src == NULL)
		return NULL;
	//在实现的时候,需要把void*转换成能进行操作的数据类型,如char*
	char *pdest = (char *)(dest);
	const char *psrc  = (char *)(src);
	int i;
	
	//dest和src有重叠且dest指向src中的元素,因此需要对src从后向前复制
	if(pdest > psrc && pdest < psrc + num)      //可以不等于 psrc + num
		for(i = num - 1; i > -1; i--)
			pdest[i] = psrc[i];
			
	//src指向dest中的元素或没有重叠(普通情况),因此需要对src从前向后复制 
	else
		for(i = 0; i < num; i++)
			pdest[i] = psrc[i];
			
	return dest;
}

int main()
{
	char src[] = "abc";
	char *dest = (src + 1);      //第一种情况
	dest = (char *)MyMemcpy(dest, src, 4);      //要强转成需要的操作类型 
	printf("%s\n", dest);
	
	return 0;
}


在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值