为了成功上岸之字符串代码总结
整数转字符串(不用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;
}