下一篇:字符串处理函数及典例(2)
目录
//已知10名同学的姓名和考试成绩,编程实现按姓名的字典顺序将其递增排序
头文件#include<string.h>
1.字符串长度测试函数strlen
格式:unsigned int strlen (char *string)
功能:测试并返回字符串的实际长度(读取到字符串结束符 '\0' 停止)。
注意:如果就想表达 '\0' 这个字符串,加上反斜杠变成 '\\0' 即可。
这里要熟练掌握转义字符的应用。其实编译器都为你做好了,仔细看字体的颜色是不是不一样?
2.字符串比较函数strcmp
格式:int strcmp(char *string1,char *string2)
功能:从左向右逐个字符比较两个字符串队对应的ASCII码值(不是比较长度),直到遇到不同字符或NULL(即 '\0' )为止,并由函数返回值返回一个比较结果的整数(正数/负数/0),VS环境下返回1、0、-1。
实现strcmp函数功能的代码段:
for (i = 0; strint1[i] == string2[i]; i++);
if (string[i] == '\0');
break;
return string1[i] - string2[i];
注意:
1)C语言中必须用strcmp函数比较两个字符串,不能用 > < == 等关系运算符比较;
2)string1,string2可以是字符串常量,一维字符数组名或一级字符指针,代表了两个字符串起始字符的地址;
3)由于字符的ASCII码值与词典的字母一致,所以利用strcmp比较字符串可以实现按字典顺序排序。
3.字符串复制函数strcpy
格式:char *strcpy(char *string1,char *string2)
功能:将string2指向的源字符串复制到string1中。字符串结束符NULL(即 '\0' )也一同复制到目标字符串中。遇到 ' \0 ' 即停止复制,可用于字符串的交换。
实现strcpy函数功能的代码段:
int i = 0;
while (str2[i] != '\0')//注意这里最后一个'\0'没有复制过去
{
str1[i] = str2[i];
i++;
}
str1[i] = '\0';//加上字符串结束符,否则目标字符串后面会出现乱码
int i = 0;
while (str1[i] = str2[i])
i++; //这样写就不需要加'\0',因为这里直接将'\0'也复制过来了
注意:
1)str1 = " hello world " ; 错
strcpy ( str1," hello world "); 对
2)strcpy函数要求目标字符串有足够的空间,否则在复制源字符串时会溢出,越界;
3)string2代表了源字符串起始字符的地址,可以是字符串常量,一维字符数组名,一级字符指针。但代表了目标字符串起始字符的地址string1只能是一维字符数组名或一级字符指针,不能是字符串常量,因为字符串常量的值不能改变。
4.字符串连接函数strcat
格式:char *strcat(char *string1,char *string2)
功能:将string2指向的字符串连接到string1指向的字符串后面。可以通过函数返回的地址string1访问连接后的新串。
注意:不能自己给自己追加,要用strncat(详见字符串处理函数即典例(2))
注意:
调用时注意事项同strcpy函数,定义string1时,数组的长度要大于等于strlen(string1) + strlen(string2) + 1,否则会出现溢出和越界。
5.大小写转换函数strupr,strlwr
格式:char *strupr(char *str)
char *strlwr(char *str)
功能:strupr()将str指向的字符串中的字符转换为大写,strlwr()将str指向的字符串中的字符转换为小写。
这里直接用strupr和strlwr编译器会报错,根据错误提示改为_strupr和_strlwr即可。(啥?你问我为啥,我也布吉岛啊,对我来说超纲了呜呜呜,哪位小可爱知道的话可以在评论区里留言哦,这里先谢过大家了哈~)
注意:
strupr()和strlwr()不会创建新串,而是改变原有字符串大小写。所以str只能是一维字符数组名或一级字符指针,不能是字符串常量,因为字符串常量的值不能改变。
6.字符串应用举例
//不用strcpy函数,编程实现复制字符串
简单点如下:
int main()
{
char arr1[20];
char arr2[] = "hello world";
int i = 0;
while (arr2[i] != '\0')
{
arr1[i] = arr2[i];
i++;
}
arr1[i] = '\0';//给最后一个赋'\0',否则会出现乱码(such as 烫烫烫烫烫烫蘉簖蜩鴾)
printf("%s\n", arr1);
return 0;
}
想要高级点??那就要指针和函数出马了:
void my_strlen(char* dest, char* src)
{
assert (dest && src);
while (*src != '\0')
{
*dest = *src;
dest++;
src++;
}
*dest = *src;//拷贝最后一个字符'\0'
}
//魔法1来了!!!
//以上代码可以等价为:
//void my_strlen(char* dest, char* src)
//{
// assert (dest && src);
// while (*dest++ = *src++)
// {
// ;
// }
//}
//至于为啥,相信聪明的你肯定知道的吧~~
//魔法2来了!!!
//根据之前的知识我们知道strcpy本质上返回char*
//这里就用char*来写个函数
//char* my_strlen(char* dest, char* src)
//{
// assert (dest && src);
// char* ret = dest;//只需传入数组首地址即可
// while (*dest++ = *src++);
// return ret;
//}
int main()
{
char arr1[20];
char arr2[] = "hello world";
my_strlen(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
这里再插入一个小知识:assert
assert(statement); —— 表达式为真啥事都不发生,表达式为假则报错
注意:assert在release版本中自动优化了
就拿上面的题来举例,如果dest或者src为NULL怎么办?程序会崩溃的,而程序员自己不知道咋错了。怎么让程序员晓得有Bug呢?
void my_strlen(char* dest, char* src)
{
//此处assert断言指针有效性,假(有一个为NULL或都是NULL)则会报错
assert(dest != NULL);
assert(src != NULL);
//或者直接简单点assert(dest&&src);
while (*dest++ = *src++)
{
;
}
}
这样就OK啦,可以准确提醒程序员哪有错误,精确到line哦~
//不用strlen函数,编程测试字符串长度
//函数
int my_strlen(const char* str)
{
assert(str != NULL);//断言指针有效性
int count = 0;
if (*str != '\0')
{
count++;
str++;
}
return count;
}
//递归
int my_strlen(const char* str)
{
assert(str != NULL);
if (*str != '\0')
return 1 + my_strlen(str + 1);
else
return 0;
}
//指针-指针
int my_strlen(const char* str)
{
assert(str != NULL);
const char* start = str;
while (*str)
str++;
return str - start;
}
//不用strcmp函数,比较两个字符串
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while(*str1==*str2)
{
if (*str1 == '\0')
return 0;
str1++;
str2++;
}
// if (*str1 > *str2)
// return 1;
// else
// return -1;
return *str1 - *str2;
}
//不用strcat函数,编程实现连接输入的两个字符串
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
char arr1[20];
char arr2[10];
printf("请输入两个数组:");
gets(arr1);//接收输入的数组arr1
gets(arr2);//接收输入的数组arr2
int i = 0;
int j = 0;
while (arr1[i] != '\0')//这一步是为了找到arr1中的'\0'对应的下标,
{ //作为arr2接入arr1的起始位置
i++;
}
for (j = 0 ; arr2[j] != '\0'; j++)//只要arr2没有到'\0',
{ //
arr1[i+j] = arr2[j]; //就循环将arr2[j]放入arr1[i+j]中对应的位置上去
}
arr1[i + j] = '\0';//将arr1结尾放一个'\0',否则会出现乱码
printf("%s\n", arr1);
return 0;
}
//编程实现将一个输入的十进制整数转换为二进制数字字符串
atoi函数和itoa函数
小Tips:库函数 atoi(头文件#include<stdlib.h>)可以把一个数字字符串转换成对应整数,格式:int atoi(const char *str);
库函数 itoa(头文件#include<stdio.h>)可以把一个输入的整数转换为字符串;
格式:char *itoa(int value,char *string,int radix),其中value为欲转换的数据;string为目标字符串的地址;radix为转换后的进制数。
这是借助函数的方法,那么不使用这两个库函数,我们能不能编程实现答案呢?
当然可以啦,不过注意是转换为字符串,不是单纯的转换为二进制数字哦~
这里用的是do-while循环,之前用的是while循环,道理都是一样的,就看你哪个用的更顺手啦~ 具体内容详见 进制转换专题
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
char arr[30];
int n = 0;
int i = 0;
printf("请输入一个整数:");
scanf("%d", &n);
do
{ //这里是转换为十进制字符
arr[i] = n % 2 + '0';//与转换为十进制数字只差了一个 +'\0'
i++;
n = n / 2;
} while (n != 0);//出循环时i为最大下标加一!
arr[i] = '\0';//将最后一个字符赋为'\0',否则会出现乱码
int l = 0;
int r = i - 1;
for (l = 0, r = i - 1; l < r; l++, r--)//生成的字符是逆序的,所以要先两两交换
{
char tmp = arr[l];
arr[l] = arr[r];
arr[r] = tmp;
}
printf("%s\n", arr);
return 0;
}
//编程实现将一个输入的小写字母口令字符串加密
字符串加密,解密的方法有很多,简单一点就是直接对字符加上或减去一个数从而变成另一个数;更进一步是将这个数换成一串复杂的密文;或干脆使用一张字符变换对照表……
这里我们就不深究了,只使用一种简单的加密思路:找出每个小写字母在26个字母中的序号,转换为从z开始计数的逆序号。将来只需再运行一遍本程序即可得到原始口令。
小写字母逆序转换(e.g.'a'--->'z','b'--->'y'……):
换后 = ' z ' - 换前 + ' a '
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
char arr1[20];
char arr2[20];
int i = 0;
printf("请输入密码:");
gets(arr1);
while (arr1[i] != '\0')
{
arr2[i] = 'z' - arr1[i] + 'a';//重点!!!
i++;
}
arr2[i] = '\0';
printf("转换后的密码是:%s\n", arr2);
return 0;
}
再将转换后的密码输入即可得到原始密码。
//已知10名同学的姓名和考试成绩,编程实现按姓名的字典顺序将其递增排序
为什么多个名字要用多维数组存储:名字是字符串,一个字符串需要一个一维数组存储,多个名字就需要多维数组。如name[10][10]={"张三","李四","王五",……};相当于"张三"占用整个多维数组的第一行,"李四"占第二行,"王五"占第三行……
int main()
{
char name[10][10] = { "张三","李四","王五","赵一","周五","钱二","孙三","冯九","吴六","郑七" };
char nametmp[10];//交换的中间值
int score[10] = { 95,74,83,90,66,89,70,92,73,86 };
int scoretmp;//交换的中间值
int i = 0;
int j = 0;
//这里的思路很像冒泡排序,两两相邻比较,边比边换
for (i = 0; i < 10; i++)//外层决定趟数,一趟解决一个姓名的位置
{
for (j = 0; j < 10 - 1 - i; j++)//内层决定每一趟比的次数
{
if (strcmp(name[j], name[j + 1]) > 0)//这里的arr[]指的是一个数组中的起始字符,也正因为这一特点我们才能根据 姓 来排序
{ //两个姓对应的ASCII码值比较,
strcpy(nametmp, name[j]); //将大的与小的交换放在后面
strcpy(name[j], name[j+1]); //注意strcpy可用于字符串的交换,这也进一步说明了每个姓名都是一个字符串,都占用一个数组
strcpy(name[j+1], nametmp);
scoretmp = score[j]; //成绩也跟着名字交换
score[j] = score[j+1];
score[j+1] = scoretmp;
}
}
}
printf("排序后的名单为:\n");
for (i = 0; i < 10; i++)
{
printf("%s\t%d\n", name[i], score[i]);
}
return 0;
}
呼 ~ 终于完成了,还是有点小成就感的哈哈哈。
有志者事竟成,破釜沉舟,百二秦关终属楚;
苦心人天不负,卧薪尝胆,三千越甲可吞吴。
要继续加油鸭!!!