本篇文章讲解一道牛客网上的华为机试题:倒置字符串
题目链接和题目详情如下:
本篇博客使用两种方法解决这道题目:
第一种方法是使用指针将空格元素改为'\0',然后用一个指向数组尾端的指针打印个个单词,这样就可以完成字符串的倒置打印,具体代码截图在下面中,并配上注释。
#include <stdio.h>
#include <string.h>
void char_arr(char arr[], int len)
{ //将空格改为'\0'
char * p = arr;
int i = 0;
for (i = 0; i < len; i++)
{
if (*p == ' ')
{
*p = '\0';
}
p++;
}
}
int main()
{
char arr[1000] = { 0 };
while (gets(arr) > 0)
{
//计算输入的数组的长度
int len = strlen(arr);
//将指针end指向arr的末端。
char* end = arr + len - 1;
//空格初始化为\0;
char_arr(arr, len);
//打印数组,直到end从末端回到数组的起始位置。
while (end != arr)
{ //当*end等于'\0’,则end位于一个单词的上一个位置。
if (*end == '\0')
{ //打印单词
printf("%s ", end + 1);
}//每次向后移动一个字节——char型指针
end--;
}
//因为end的地址等于arr就停止了,所以第一个单词没有打印,需要额外打印一次.
printf("%s", end);
}
return 0;
}
这里注意几个点:
1.计算数组的长度时,一定要在将空格换为'\0'之前进行计算。
2.end指向的arr+len-1,一定要减1,这样end才指向arr最后一个字符,而不是指向'\0',如果指向'\0',那么进入while的第一次就会打印,打印出一个多余的空格,因为while循环中的打印%s+空格。
3.因为end的地址等于arr就停止了,所以第一个单词没有打印,需要额外打印一次,即在while循环结束后再打印一次,这样就不会漏掉第一个单词.
第二种方法:翻转法。
这个办法的思路是:
1.先翻转整个数组。
2.再翻转每个单词。
3.打印数组。
#include <stdio.h>
#include <string.h>
void reverse(char* arr, int len)
{
char* left = arr;
char* right = arr + len - 1;
char temp;
while (left < right)
{
temp = *left;
*left = *right;
*right = temp;
right--;
left++;
}
}
int main()
{
char arr[1000] = { 0 };
while (gets(arr) > 0)
{
int len = strlen(arr);
char* p = arr;
reverse(arr, len);
printf("%s\n", arr);
while (*p != '\0')
{
int count = 0;
char* temp_p = p;
while (*p != '\0'&& *p!=' ')
{
count++;
p++;
}
reverse(temp_p, count);
if(*p!='\0')
p++;
}
printf("%s\n", arr);
}
return 0;
}
注意的点:
1.reverse函数中,只需要left<right就行了,不需要等于,因为中间的一个元素不用调换,减少一次翻转次数。
2.再进行第二次翻转时间,要将单词的起始地点和单词的长度传入到reverse函数,所以要定义一个temp_p指针接受这次单词的起始地点,因为p是不断运动的。
3.在判断单词的结束标志时,使用&&关系式,因为要保证*p不是空格并且*p不是'\0'时,p就停止向后+1。
4.在p++时要加上一句if(*p!='\0'),因为当最后一次p指向'\0'时,如果再让p++,就会让p指针跳过了'\0',这是不允许的。
当然,这里面reverse的参数用两个指针也是可以的,一个指向字符串首段,一个指向末端,也是一种很方便的方法,思路大抵相同。
这道题有两种解决方法,但是再这题中,方法一很明显更方便,但是也不容易想到,所以在后面也使用了翻转法来解决这道题,方便我们领悟翻转的思路,注意一些编程的细节。
这里给大家举例几个多组输入的方式:
while(~scanf("%d",&a))
whlie(scanf("%d",&a)!=EOF)
whlie(scanf("%d",&a)==1)
while (scanf ("%d %d",&a,&b)==2)
while(scanf("%d %d",&a,&b)!=EOF)
while (~scanf("%d",&temp))
字符串的多组输入:
while(gets(arr)>0)
使用scanf完成带有空格的字符串输入
while(scanf("%[^\n]",arr)
如果在VS等编译器上使用以上的输入方式,如果出现的不可控制的死循环,可以使用
while(temp=getchar()!='\n)
来清空缓冲区的数据,来保证scanf输入的时候不会直接从缓冲区中拿取数据,从而跳过从键盘输入,变得不可控。