问题:有一个字符数组的内容为:"student a am i",请你将数组的内容改为"i am a student".
要求:不能使用库函数。只能开辟有限个空间(空间个数和字符串的长度无关)。
思路分析:首先,大家会想到我把每个先将整个数组前后交换,这样的思考方式就会出现“i ma a tneduts”,这样的话就会出现单词的反转了,我们再让每个单词翻转过来就行了。
这里的翻转在重复的使用,所以我们把翻转的步骤封装为一个函数,只要找到翻转的前面和后面,就可以完成翻转,所以需要两个字符指针:*left 和 *right
代码实现:
(1)交换函数:
void reverse(char *left, char *right)
{
assert(left); //断言指针是否为空,如果是空指针就结束,不进行下面步骤
assert(right);
while (left < right) //用于交换的主函数,如果传来要交换的头地址和尾地址,就可以完成交换
{
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
图解:
(2)交换函数写完后我们就需要传址交换了,
第一步:需完成整个字符串的交换,将字符串的第一个元素和最后一个字符(\0的前一个字符)地址传进去,然后实现交换;
第二步:将每个单词交换,我们开始可能会想到我手动的将他们每个单词的地址传进去,不就实现了吗?但是电脑的出现不就是为了让人更加便利吗?所以我们通过思考会发现,这些单词的截止处不是‘ ’(空格)就是‘\0’,所以我们以这个为截止,开始将单词的起始位置记住,进行双层循环是不是就可以实现了呢?
代码如下:
void strReverse(char *str, int sz)
{
assert(str);
reverse(str, str + sz - 1); //用于逆置整个字符串
while (*str != '\0') //用于逆置每个单词
{
char *p = str; //记住每一个单词的起始位置
while ((*str != ' ') && (*str != '\0')) //找寻每个单词的终止位置
{
str++;
}
reverse(p, str - 1); //找到空格处,前一个就为单词的最后一个字母
if (*str != '\0')
{
str++;
}
}
}
图解:
全部代码:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
void reverse(char *start, char *end) //用于逆序整个字符串
{
assert(start);
assert(end);
while (start < end)
{
char* tmp = *start;
*start = *end;
*end = tmp;
start++;
end--;
}
}
void strReverse(char *str, int sz) //用于逆序一个单词
{
assert(str);
reverse(str, str + sz - 1);
while (*str != '\0')
{
char *p = str;
while ((*str != ' ') && (*str != '\0'))
{
str++;
}
reverse(p, str - 1);
if (*str != '\0')
{
str++;
}
}
}
int main()
{
//1、让整个语句逆序:i ma a tneduts
//2、让每个单词逆序:i am a student
char arr[] = "student a am i";
int sz = strlen(arr);
strReverse(arr, sz);
printf("%s\n", arr);
system("pause");
return 0;
}