题目
请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.
则经过替换之后的字符串为We%20Are%20Happy.
背景
在网络编程中,如果URL参数中含有特殊字符,如空格、#
等,可能导致服务器端无法获得正确的参数值。我们需要将这些特殊符号转换成服务器可以识别的字符。转换的规则是在%后面跟上ASCII码的两位十六进制的表示。比如空格的ASCII码是32,即十六进制的0x20,因此空格被替换成%20
。再比如 # 的ASCII码为35,即十六进制的0x23,它在URL中被替换为%23
.
初始思路
这个是我想出来的单指针法,首先先遍历一次字符串,获得空格的个数,然后根据空格的个数确定改变之后的字符串的长度!
首先我定义了两个len用来获取关检位置的指针,还是先将字符逐个移动,然后遇到空格的时候需要一定的指针运算才能实现!
void my_replace(char * str)
{
int k_num = 0;//定义空格数目
int add_num = 0;
int len = 0;//新字符串的长度
int len2 = 0;
char *m_str = str;
assert(str != NULL);
while (*m_str++)
{
if (*m_str == ' ')
k_num++;
}
len2 = strlen(str) + 2 * k_num;
len = strlen(str);
int i = 0;
m_str = str + len;
while (*m_str != *str)
{
//如果遇到的不是空格
if (*m_str != ' ')
*(m_str + 2*k_num) = *m_str;
else
{
*m_str = '%';
*(m_str + 1) = '2';
*(m_str + 2) = '0';
for (i = 2; i >=0; i--)
*(m_str + i + 2) = *(m_str + i);
}
m_str--;
}
}
但是这种实现方式不太容易理解,代码量也是非常多!
更加高效的解法
我们可以先遍历一次字符串,这样就能统计出字符串中空格的总数,可以山此计算出替换之后的字符串的总长度。每替换一个空格,长度增加2,因此替换以后字符串的长度等于原来的长度加上2乘以空格数目。我们还是以前面的字符串”We are happy.”为例,”We are happy.”这个字符串的长度是14(包括结尾符号’\0’),里面有两个空格,因此替换之后字符串的长度是18!
使用两个指针轻松解决此问题:
如图,p1指针指向\0,p2指针指向我们预期结果的字符串的末尾:
- 逐个字符复制,p1向前走一步同时p2向前走一步就复制一个字符,直到p1遇到空格就停止
- 当p1遇到空格的时候,p2连续做三次减法,同时分别赋值为
%
、2
、0
,p1在向前走一步准备开始下一轮复制字符 - 同样的道理循环开始下一轮复制,p1指针一直再往前走,只要p1走到字符串开头的位置便停止循环
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
void my_replace2(char * str)
{
char *p1 = NULL;
char *p2 = NULL;
int len = 0;
assert(str != NULL);
len = strlen(str);
p1 = str + len;
p2 = str + len + 4;
while (*p1 != *str)
{
if (*p1 != ' '){
*p2 = *p1;
p2--;
p1--;
}
else
{
p1--;
*(p2--) = '0';
*(p2--) = '2';
*(p2--) = '%';
}
}
}
int main(void)
{
char str[30] = "we are happy";
// "we%20are%20happy";
printf("%s\n",str);
my_replace2(str);
printf("%s\n", str);
system("pause");
}
考点
1、考查对字符串的编程能力。
2、考查分析时间效率的能力。我们要能清晰地分析出不同方法的时间效率各是多少。
3、考查对内存覆盖是否有高度的警惕。在分析得知字符串会变长之后,我们能够意识到潜在的问题,并主动和面试官沟通以寻找问题的解决方案。
4、考查思维能力。在从前到后替换的思路被面试官否定之后,我们能迅速想到从后往前替换的方法,这是解决此题的关键。