C语言学习4: 函数返回值与传入参数,关于函数值传递和类型隐性转换,变量不同的作用域,static变量,多文件编译例如两个C文件,显示函数调用语句跳转,递归,斐波那契数列,多文件编译相同变量的问题。
1,函数返回值与传入参数
#include <stdio.h> void foo(void); // 如果不声明返回值类型, 那么返回值类型默认为int bar(void); // 声明没有带参数, 那么调用时可以传递任意参数. void test(); //void test1(void); int main(void) { foo(); printf("world.\n"); bar(); test(3.14, "hello", 123); //test1(1, 3.14, "hello"); return 0; } void foo(void) { printf("hello "); } bar(void) { printf("-------------\n"); } void test() { } void test1(void) { }
结果:
hello world.
-------------
没有返回值会报警告,虽然默认是整形。向已经void的参数传入值,这个是错误的行为,void test1(void)的用法就是
2,关于函数值传递和类型隐性转换
#include <stdio.h> int add(int l, int r) { return l + r; } int main(void) { int a = 3, b = 5; int ret; double d1 = 3.14, d2 = 2.56; double dret; // C语言函数调用时, 参数是值传递(看着赋值) ret = add(a, b); printf("ret = %d\n", ret); // 传参过程中发生隐式类型转换 dret = add(d1, d2); printf("dret = %lf\n", dret); return 0; }
结果:
ret = 8
dret = 5.000000
强制转换成双精度。
3,变量不同的作用域
#include <stdio.h> /* * scope (表现在编译期 compiler time) *1. 全局作用域, 从变量声明处开始, 到本文件结束. *2. 函数作用域, 从变量声明处开始, 到函数结束. *3. 语句块作用域, 从变量声明处开始, 到语句块结束. * *1. 同一作用域中, 变量不能重定义. *2. 内层作用域同名变量隐藏外层作用域同名变量. */ /* * lifetime (表现在运行期 runtime) *1. 全局变量/静态变量在程序开始时存在, 一直到程序运行结束. * 存放在静态存储区(.data segment, .bss segment) *2. 局部变量在函数调用时开始存在, 函数调用结束后消失. * 存放在动态存储区, 即运行栈(runtime stack)上. */ int a = 86; void foo(void) { int a = 76; printf("----foo---- a = %d\n", a); { int a = 36; printf("==foo==block, a = %d\n", a); } printf("----foo---- a = %d\n", a); } int main(void) { printf("in main, a = %d\n", a); foo(); return 0; }
结果:
in main, a = 86
----foo---- a = 76
==foo==block, a = 36
----foo---- a = 76
可以看出,全局变量和局部变量一样的话,以局部变量优先
4,static变量
#include <stdio.h> void foo(void) { static int a; a++; printf("a = %d\n", a); } void bar(void) { int a = 0; a++; printf("a = %d\n", a); } int main(void) { int i; for (i = 0; i < 5; i++) foo(); printf("-----------\n"); for (i = 0; i < 5; i++) bar(); return 0; }
结果:
a = 1
a = 2
a = 3
a = 4
a = 5
-----------
a = 1
a = 1
a = 1
a = 1
a = 1
静态局部变量是想让局部变量在下次调用此函数时保留上次运行的结果。每次使用就是赋值。如果初始化不赋值的,编译自动赋值0(数字型变量)空格(字符型变量)
自动变量就是不确定的值了。register变量则是需要频繁运算用到的变量可以用,说白了就是使用寄存器节约时间。
5,多文件编译例如两个C文件。
5main.c
#include <stdio.h> void foo(void); int main(void) { foo(); return 0; }
5foo.c
#include <stdio.h> static void foo(void) { printf("this is 5foo.c\n"); }
编译方法:两种编译只是为了让人了解而已
will@will-Inspiron-N4010:~/c/3rd$ gcc -c 5main.c will@will-Inspiron-N4010:~/c/3rd$ gcc -c 5foo.c will@will-Inspiron-N4010:~/c/3rd$ gcc -o 5 5main.o 5foo.o will@will-Inspiron-N4010:~/c/3rd$ ./5 this is 5foo.c will@will-Inspiron-N4010:~/c/3rd$ gcc 5main.c 5foo.c will@will-Inspiron-N4010:~/c/3rd$ ./a.out this is 5foo.c
6,显示完整语句执行过程
#include <stdio.h> void foo(void) { printf("foo"); } void bar(void) { printf("bar --> "); foo(); printf(" <<= bar"); } int main(void) { printf("main --> "); bar(); printf(" <<= main"); putchar('\n'); return 0; }
结果:
will@will-Inspiron-N4010:~/c/3rd$ ./a.out
main --> bar --> foo <<= bar <<= main
7,递归应用
#include <stdio.h> unsigned add(unsigned n) { if (n == 1) return 1; return n + add(n - 1); } unsigned add_recursive(unsigned n) { unsigned tmp; if (n == 1) { printf("这是第 %d 层返回.\n", n); return 1; } printf("这是第 %d 层调用.\n", n); tmp = n + add_recursive(n - 1); printf("这是第 %d 层返回.\n", n); return tmp; } int main(void) { unsigned n; printf("pls input n: "); scanf("%d", &n); printf("1 + 2 + ... + %d = %d\n", n, add_recursive(n)); return 0; }
结果:
pls input n: 5
这是第 5 层调用.
这是第 4 层调用.
这是第 3 层调用.
这是第 2 层调用.
这是第 1 层返回.
这是第 2 层返回.
这是第 3 层返回.
这是第 4 层返回.
这是第 5 层返回.
1 + 2 + ... + 5 = 15
层层深入,又从中间层层跑出。又一个来回。
8,使用递归求解的斐波那契数列
#include <stdio.h> unsigned fibonacci(unsigned n) { if (n == 1) return 1; if (n == 2) return 1; return fibonacci(n - 1) + fibonacci(n - 2); } unsigned fibo_sum(unsigned n) { if (n == 1) return 1; return fibonacci(n) + fibo_sum(n - 1); } int main(void) { unsigned n; printf("input n: "); scanf("%d", &n); printf("第 %d 项: %d\n", n, fibonacci(n)); printf("前 %d 项和: %d\n", n, fibo_sum(n)); return 0; }
结果:
input n: 6
第 6 项: 8
前 6 项和: 20
1 1 2 3 5 8
9,两个C文件编译的变量的用法
9main.c
#include <stdio.h> int gvar_main1 = 36; int gvar_main2 = 48; int foo(int, int); int main(void) { int ret; ret = foo(gvar_main1, gvar_main2); printf("ret = %d\n", ret); return 0; }
9foo.c
int gvar_foo1 = 66; int gvar_foo2 = 88; int add(int l, int r) { return l + r; } int foo(int l, int r) { return gvar_foo1 + gvar_foo2 - add(l, r); }
结果:
will@will-Inspiron-N4010:~/c/3rd$ gcc 9main.c 9foo.c will@will-Inspiron-N4010:~/c/3rd$ ./a.out ret = 70
结果就是C文件函数的变量互不通用,编译器链接的是函数