最近我参加了一次采访,有几个问题,我必须找到代码中的缺陷。以下是问题。
void fun(char *p)
{
int a = 0;
int b = strlen(p) - 1;
int d = 0;
while(d == 0)
{
if(a == b)
{
d = 1;
}
else
{
char t = *(p + a);
*(p + a) = *(p + b);
*(p + b) = t;
a += 1;
b -= 1;
}
}
}
我的回答是:
NULL
检查p
。 if(a == b)
。如果字符串的长度是偶数,则这种情况永远不会满足。 如果有人发现任何其他缺陷,请告诉我,并且欢迎对我给出的答案发表任何评论。
答案 0 :(得分:5)
代码的目的是在分配字符串的位置反转字符串。问题是:
<强>错误强>
正如您已经指出的那样,a==b
仅适用于奇数长度的字符串。可能是面试问题所寻求的。
(检查p
是否为NULL可能是必要的。你无法从发布的代码中看出来:它取决于函数的文档。对于通用函数,最好留下它检查来电者。)
编码风格
p[a]
是*(p + a)
之前的首选,因为它更具可读性。while(a < b)
,这也将修复上述错误。size_t
代替int
。应该将代码重写为类似的内容(未经测试):
#include <string.h>
void str_reverse (char* str)
{
size_t start = 0;
size_t end = strlen(p) - 1;
while(start < end)
{
char tmp = str[start];
str[start] = str[end];
str[end] = tmp;
start++;
end--;
}
}
请注意,现在实际上不再需要注释,因为变量和函数名称使代码自我记录。
答案 1 :(得分:4)
第一次转化:d
只能是0
或1
。它只能在while
循环条件下读取。实际上,是循环条件,函数体可以重写为:
int a = 0;
int b = strlen(p) - 1;
while(a != b)
{
char t = *(p + a);
*(p + a) = *(p + b);
*(p + b) = t;
a += 1;
b -= 1;
}
三线区块肯定是交换。在C ++中你可以使用实际的std::swap
函数,但是在没有泛型函数和重载的情况下,我猜这样做是很好的。让我们对它进行评论并使用索引表示法:
// Swap p[a] and p[b]
char t = p[a];
p[a] = p[b];
p[b] = t;
a += 1
和b -= 1
也可以重写为++a
和--b
。
现在很明显,这个函数使用两个索引a
和b
,它们从两端开始并在中心相交,在路上交换索引字符。它是一个就地字符串反转功能,所以我们将其重命名(和p
)。 a
和b
也可以重命名,但IMO足够清楚。
void reverse(char *str)
(从Lundin的答案中删除),a
和b
是数组中的索引,其选择类型应为size_t
。
size_t a = 0u;
size_t b = strlen(str) - 1u;
现在,你发现的错误:的确,如果strlen(str)
是偶数,a
和b
将在中间相互超越,永远不会相等。让我们改变条件来解释这个问题:
while(a < b)
最后,处理str == NULL
:这个功能非常低级。对空指针做出反应没有什么用处,所以只要添加一个可理解的失败条件:
assert(str && "Please provide a non-null pointer.");
最终产品:
void reverse(char *str)
{
assert(str && "Please provide a non-null pointer.");
size_t a = 0u;
size_t b = strlen(str) - 1u;
while(a < b)
{
// Swap str[a] and str[b]
char t = str[a];
str[a] = str[b];
str[b] = t;
++a;
--b;
}
}
答案 2 :(得分:0)
void reverse(char *s){
for(char *end=s+strlen(s)-1; s<end; ++s,--end)
*s^=*end^=*s^=*end; //xor swap
}
除了:
while(1) { ... if (a==b) break; else...}
while(a!=b){...}
while(a<=b)
while(a<b)...