目录
一、表达式的左值与右值
课上我的大学C语言老师在讲赋值表达式时,
如:int a = 10;
告诉我说这句话的意思是将10赋给变量a,我也就不求甚解的记了下来。但当深入了解时,尤其是学到指针表达式时总会觉得不是那么透彻。有时报错时也会显示xxx不能作为左值。在了解左值与右值后才逐渐理清。
在上一篇文章中提到,C语言是以变量名来访问内存的,也就是说它用变量名替代了汇编中的地址。此时我们再看这个赋值表达式,这句话表达的就是分配一个地址给a,之后将10存入这个地址。自然,等号左边的被称为左值,等号右边的被称为右值;左值是一个地址,右值是一个数值。这正相当于51汇编中的MOV指令。
现在再来看下列程序段:
int a = 10 ;
int b ;
b = a ;
最后一行中b作为左值,是其所被分配的地址,而变量a作为右值是a的值。
再看看一句错误的语句: 0 = 1 ;
这句话中0是常量,不能当作一个地址,也不能被赋值,故发生错误。
二、指针表达式
对于一个指针变量p与其表达式来说,也会有左值和右值的区别。在没有括号时我们对于一个表达式进行分析时是从右向左分析的。在不考虑多级指针情况下:
1、如果表达式内 & 多,那么其不能做为左值地址。
2、如果没有 * 和 & ,或者两者一样多,则既可作左值又可作右值。
3、如果 * 多,那么从右到左按顺序分析,最后一个操作落到 * 上, 基本上左右值都能做,否则只能是右值。
三、函数的参数
1、传给函数的值实际上是该参数的一份拷贝,即使在函数中改变传入的值也不影响该参数在函数外部的值。
2、如果想改变该参数的值,可以使用指针的方法,向函数中传递指向希望修改的变量的指针。
3、因为数组参数也相当于一个指针,故直接传递数组会改变数组实际的值。
void fun(int *a , int *b , int x , int y)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
temp = x;
x = y;
y = temp;
}
在上面这个函数中,a和b是会互换的,而x和y不会互换。
而调用这个函数应采用以下格式:
fun(&a , &b , x , y);
四、递归与迭代
递归与迭代十分相似,但在实现的过程中又不尽相同。迭代就是用while循环直到满足条件。而相较于迭代,递归函数调用时的执行过程显得很有意思。
print_int(unsigned int num)
{
unsigned int quotient;
quotient = num / 10;
if(quotient != 0)
print_int(quotient);
putchar(num % 10 + '0');
}
上面这个函数就是利用递归输出整数。此函数运行时变量被创建在堆栈中。如果输入一个数1234
num | quotient |
1234 |
执行除法后,
num | quotient |
1234 | 123 |
进入递归,
num | quotient |
123 | |
1234 | 123 |
到最后一个循环,
num | quotient |
1 | 0 |
12 | 1 |
123 | 12 |
1234 | 123 |
quotient为零时满足条件,开始由上向下出栈,并且执行 putchar(num % 10 + '0');
可以见得,递归虽然易于书写,但其执行过程是比较复杂的,尤其是对于复杂过程来说。