
“运行结果怎么和自己推导的不太一样”发出这样疑问的场景并不少见但其原因各有不同早已熟悉并精通编程的开发者们可能会偶尔出现推导的失误而初学者的问题更可能出现在基础的阅读代码的顺序上。intmain(){intarr[10]{0,1,2,3,4,5,6,7,8,9};printf(%d\n,arr[7]);inti0;while(i10){printf(%d\t,arr[i]);ii1;}return0;}这便是曾让我倍感困惑的元凶之一——由printf函数和while语句组成的简单代码及其运行结果。在思考它的运行过程时我提出了这样一个基础性问题“既然ii1且i的初值为0第一个被打印出的怎么不是下标为1的数组元素arr[1]呢”更加熟悉“数学思维”的我将i i 1;视为了“已知条件”后再去阅读上一行代码printf(%d\t,arr[i]);推导标准输出流的内容printf函数打印输出的结果也由此出错。对代码运行的时序性遵从由上至下的逻辑顺序运行的忽略成为了让我产生困惑的肇因重视起“时序思维”的建立正是让初学者们适应并尝试理解代码运行逻辑的关键也能帮助我们在术语描述中注意到更多细节——接下来我将以该代码的while循环为例更加详细地描述其运行过程我们首先在循环体外定义并初始化了循环控制变量i并将整数值0写入i的内存单元int i 0;。接下来是while迭代语句先取变量i的当前值右值0而后执行关系运算符将右值与10进行关系运算产生临时的纯量结果0或1对纯量值进行归零检测判断是否为0控制转移若为真【归零检测结果为非0】则顺序进入循环体调用printf函数——接收两个实参格式字符串%d\t和下标表达式arr[i]的右值数组第i个元素的当前值printf函数将格式化后的数据写入标准输出流迭代更新执行更新操作i i 1;将i的值增加1并写回i的内存单元随后跳转循环体末尾执行完毕后控制流无条件跳转回循环条件判断处i 10循环终止当i被更新到10时1010为假【归零检测结果为0】控制流跳出循环体顺序并执行下一条语句return 0;。在本例中下标与元素的数值恰好相同0-9但二者在语义上截然不同。本段代码还有一个初学者时常误解的地方printf(%d\n,arr[7]);中下标运算符方括号[]内的数字代表的是数组元素的偏移量下标而不是元素的个数或元素本身。只知道时序思维的字面意思不足以让我们“理解”代码能够借助时序思维意识到代码运行时连续的动态过程才是进步的关键。尝试跟随以上描述的思路结合代码进行仔细阅读后相信你会有所收获。接下来随着学习的深入我也遇到了新的问题……“如何针对变量在代码中的不同出现点判断其角色”局部变量和全局变量的概念很好理解让我产生疑问的另有其码——intAdd(intx,inty){intz0;zxy;returnz;}intmain(){intn10;intn20;scanf(%d %d,n1,n2);intsumAdd(n1,n2);printf(%d\n,sum);return0;}在Add函数的定义体中出现在代码不同位置的变量z都充当了什么角色int Add(int x, int y){int z 0;z x y;return z;}通过上下文理清代码运行的动态过程是解决问题的关键Add函数被调用后接收传入对应其形参x和y的实参【定义性出现】进入函数体后定义并初始化局部变量z分配栈内存并写入初值0【左值引用】随后执行赋值运算将x与y右值的加和写入z的内存地址左值【右值引用】最后通过return语句将z的当前值作为函数返回值返回。当然了我们可以采用更简洁的方法定义Add函数int Add(int x, int y){return(x y);}但为了消除心中的疑惑并打下坚实的编程基础思考并理解对前者的描述十分必要。关于该代码中被调用的printf函数我又想到了一个初学者们可能提出的问题为什么把sum作为参数传给printf时不需要前加取地址符呢如果你的确受此困扰可以看看接下来的内容是否能为你提供些许帮助在C语言中函数参数传递是值传递。输入函数scanf会将我们敲出的数字存入变量x的内存地址要想精准地完成对原变量的修改必须先通过取地址符得到变量的内存地址。printf(%d\n,sum);中sum出现在printf的函数参数列表内位于等号右侧的表达式求值语境它自动作为右值参与传递。printf函数作为一个负责读取数据并格式化显示的工具传递的是变量内存单元中存储的具体数值编译器会自动取出传递的变量名所对应的数值副本并作为实参传入printf函数。如果将其改为printf(%d\n,sum);格式说明符%d与实参类型int*不匹配会触发C语言标准的未定义行为程序行为不可预测且编译器会发出类型警告。“自定义函数和main函数的返回值在用途和接收对象上有什么区别”为什么Add函数要返回计算结果而main函数只返回0它们的返回对象是什么返回值的用途取决于函数在软件体系中的层级。【Add函数】int Add(int x, int y){int z 0;z x y;return z;}不考虑指针修改的前提下返回值是C语言中被调函数向主调函数传递数据的唯一标准通道。作为工具函数Add函数的作用就是计算并告知结果Add传回z的值后main函数才知道n1n2的计算结果是多少。在return z;中z代表内存中存储的具体数值充当返回值来源。函数返回时z的栈帧已被销毁CPU寄存器会将z当前数值的一份副本传递给调用方因此main函数收到的其实并非变量z本身。【main函数】int main(){int n1 0;int n2 0;scanf(“%d %d”,n1,n2);int sumAdd(n1,n2);printf(“%d\n”,sum);return 0;}main函数在软件体系中的作用是协调程序执行并向系统汇报最终结果。Add函数的计算结果在执行printf函数时已经通过标准输出流显示在屏幕上main的返回值无需用以传递业务数据。操作系统及启动程序的父进程会通过返回值判断程序的退出状态返回值0代表正常执行完毕非0为异常或特定的错误码。return 0;更改为return sum;后当sum的值不为0时操作系统会解读其为异常后续的自动化脚本也可能因检测到非零状态码中断执行。关于“与0比较的指令”前文提到的while是为了控制循环跳转main的返回值是为了向系统汇报程序状态要注意二者的不同之处。以上便是本篇博客的全部内容如有错漏还望您不吝赐教我会努力提升自己的写作质量并持续分享所学所获共勉