C语言函数相关陷阱。
在C语言中,数组参数是以引用形式进行传递的,也就是传址调用,而标量和常量则是按值传递。在函数中对标量参数的任何修改都会在函数返回时丢失,因此,被调用函数无法修改调用的函数以传值形式传递给它的参数。然而, 数组参数的其中一个元素时,调用函数所传递的数组就会被实际的修改。
上面这段话说明C语言函数参数调用时是以传值的方式进行调用,如果对这个概念理解不深刻这会导致一些我们难以发现的错误发生。
下面这个函数希望能修改调用程序传递的参数,这个程序的目的时交换调用程序所传递的这两个参数的值。
void swap(int x,int y)
{
i nt temp;
temp=x;
x=y;
y=temp;
}
这个程序看似没有任何问题,但是他并不能实现两个参数的值进行交换,原因就在于函数调用.这意味着函数将获得参数值的一份拷贝,拷贝值的改变并不会修改参数本身。
正确的交换两个参数的值的函数应该是下面这个程序:
void swap(int *x, int *y)
{
int temp;
temp=*x;
*x=*y;
*y=temp;
}
这里将两个函数的形参修改成两个指针,调用函数时向函数传递指向所希望修改的变量的指针,接着函数必须对指针使用间接访问操作,修改需要修改对变量。
这里就引出另一种函数参数调用方式“传址调用”,C语言规定所有的参数都是传值调用。但是当传递的参数是一个数组名,并且在函数中使用下标引用该数组的参数,那么在函数中对数组元素进行修改时,实际上修改的是调用程序中的数组元素,这样看来好像跟函数的传址调用相悖,但是其实并不是,数组名实际上是一个指针,传递给函数的就是这个指针的一份拷贝,对指针执行间接访问操作,访问的就是指针指向的内存位置,对他进行修改就会改变原本的值。
逻辑操作符的“短路求值”
逻辑操作符&&和||。这两个操作符看上去有点像位操作符,但它们的具体操作大相径庭,它们用于对表达式求值,测试他们得知是真还是假。
看一下下面的两个程序,试着写出a,b的值。
程序1:
int a=1;
int b=2;
if((a--<0)&& (b++>0) )
{
…………
}
程序2:
int a=1;
int b=2;
if((a--==0)|| (b++>0) )
{
…………
}
显而易见程序1 if语句判定条件为假,程序2的判定条件为真,那么if语句执行之后a和b的值分别是多少?答案是:a=0,b=2;两个程序中的b的值都没有改变,这说明if语句只对逻辑操作符的左边的表达式进行了操作。
逻辑操作符工作原理:&&操作符的左操作数总是首先进行求值,如果它的值为真,然后才会接着对右操作数进行求值,如果它的值为假,那么右操作数便不再进行求值,因为整个表达式肯定为假,右操作数的值无关紧要。||操作符也有相同的特点,他首先对左操作数进行求值,如果为真,右操作数则不再进行求值,此表达式为真,只有左操作数为假时才对右操作数进行求值。这个行为成为从“短路求值”。
有关sizeof()运算符以及strlen()函数的数据类型陷阱:
首先需要注意一下sizeof()他是一个单目运算符并非函数,作用是获取某个数据类型所占用空间的字节数,这里需要知道他所返回的数据类型时无符号类型。那么他这里有什么陷阱呢?看一下下面这个程序:
int arr[]={23,34,12,45,67,238,15};
#define TOTAL (sizeof(arr)/sizeof(arr[0]))
main()
{
int d=-1,x;
if(d<=TOTAL-2)
x=arr[d+1];
/*……*/
}
上面这个程序在执行过程中if语句当中的表达式的值位假,是否有点出乎意料,下面我们来解释一下。
在这个程序中TOTAL的数据类型是无符号类型int(unsigned int)这是由于sizeof()的返回类型是unsigned int,而变量d初始化为signed int 数据类型,if语句会测试两个数据类型的相等性,会将d升级为unsigned int类型,而-1转化成无符号类型的结果将是一个非常巨大的正整数,这会导致表达式的值为假,所以这里我们要将TOTAL进行强制类型转换,
if(d<=(int)TOTAL-2)
strlen()函数是用来计算一段字符串的长度(注意字符串的结尾nul并不计算在内),这个函数的返回值类型也是一个无符号数据类型,当在表达式当中使用它时也可能导致不可预料的结果。下面两个语句:
if(strlen(x)= strlen(y))……
if(strlen(x) - strlen(y)>=0)……
l两个语句看似相等但其实它们并不相等。第一条语句将按照你预想的那样工作,但第二条语句的结果将永远为真。Strlen函数的结果为无符号数,所以操作符>=左边的表达式也将是无符号数,而无符号数绝对不会是负数。
当表达式当中同时包含无符号数与有符号数,可能会产生奇怪的结果。和上面一对语句一样,下面两条语句并不相同:
if(strlen(x)>=10)…….i
if(strlen(x)-10>=0)…….
如果将strlen的返回值强制类型转换成int,就可以消除这个问题。
所以说代码中尽量减少无符号数的使用,以免增加不必要的复杂性。