字符实际上是一些ascii数字。那么为什么下面的代码,它应该交换两个字符,给出错误的结果
void swap(char *a,char *b)
{
*a=*a+*b;
*b=*a-*b;
*a=*a-*b;
}
答案 0 :(得分:4)
理论上,这个计算看起来不错。让我们通过例子来解决它:
我们来看a = 'S' = 83
和b = 'O' = 79
。
a = a + b = 83 + 79 = 162
如果您的编译器将char
定义为无符号,则溢出没有问题。如果您的编译器定义了要签名的char
,则超出范围(> 127)并生成a = -94
。
b = a - b = (-94) - 79 = -173
再次超出范围并收益83,这没关系。
a = a - b = (-94) - (-173) - = 79
这看起来也不错。
实际上,这段代码对我没有任何问题:
char a = 'S', b = 'O';
swap(&a, &b);
assert(a == 'O');
assert(b == 'S');
使用您提供的确切swap
功能。
答案 1 :(得分:4)
如果上面的表达式会导致算术溢出,结果会很奇怪。如果指针a
和b
指向同一位置 * ,上述方法也将失败。
试试这个:
void swap(char *a,char *b)
{
if (a == b) // Check if the two addresses are same
return;
*a=*a^*b;
*b=*a^*b;
*a=*a^*b;
}
*如果a
和b
指向同一位置,请说x100
并让存储在该位置的值为0111
(二进制),则:
*a = *a ^ *b // *a will have now 0000
*b = *a ^ *b // *b = 0000^0000 = 0000
*a = *a ^ *b // *a = 0000^0000 = 0000
答案 2 :(得分:1)
两个问题
您的上一行*a=*a-*b;
实际归结为*a=*a-*a;
char
可以是signed
或unsigned
。这是编译器的选择; C标准允许。因此*a-*b
的价值可能因平台而异。
可以在没有临时的情况下进行交换。该技术(XOR交换)已有详细记录,但由于一些令人讨厌的边缘情况,因此不建议使用它。
答案 3 :(得分:0)
如果指针相等,这将不起作用。所以这需要先检查和处理。
要找出您机器上的问题,您应该编写如下所示的测试,并使用其他printf输出分析结果,例如:
void swap(char *a, char *b)
{
/* if (a != b){ */
*a = *a + *b;
*b = *a - *b;
*a = *a - *b;
/*}*/
}
void swapTemp(char *a, char *b)
{
char temp = *a;
*a = *b;
*b = temp;
}
int
main(){
unsigned int errors = 0;
int b;
for (b = 0; b <= 255; b++)
{
int a;
for (a = 0; a <= 255; a++)
{
char a_swap = a;
char a_swapTemp = a;
char b_swap = b;
char b_swapTemp = b;
swap(&a_swap, &b_swap);
swapTemp(&a_swapTemp, &b_swapTemp);
if ((a_swap != a_swapTemp) || (b_swap != b_swapTemp))
++errors;
/* extend to print results here to analyse the problem */
}
}
printf("There where %u errors!", errors);
return 0;
}
提供有关您的机器,编译器和测试结果的更多信息!