C语言04函数与递归

1 函数的定义

1.1 问题

自定义两个简单的函数,使用return返回数据。

1.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:函数的定义

代码如下所示:

  1. #include <stdio.h>
  2. int getInt()
  3. {
  4. return 10;
  5. }
  6. double getDouble()
  7. {
  8. return 5.5;
  9. }
  10. int main()
  11. {
  12. int n;
  13. n = getInt();
  14. printf ("%d\n", n);
  15. double d;
  16. d = getDouble();
  17. printf("%lf\n", d);
  18. return 0;
  19. }

上述代码中,以下代码:

  1. int getInt()
  2. {
  3. return 10;
  4. }

定义了一个函数getInt,该函数返回一个整型数据,没有参数。

上述代码中,以下代码:

  1. double getDouble()
  2. {
  3. return 5.5;
  4. }

定义了一个函数getDouble,该函数返回一个双精度浮点型数据,没有参数。

上述代码中,以下代码:

  1. int n;
  2. n = getInt();
  3. printf ("%d\n", n);

首先,定义一个整型变量n,用于存储getInt函数的返回值。

然后,调用函数getInt得到返回值,并存储在变量n中。

最后,使用函数printf输出变量n的内容。

上述代码中,以下代码:

  1. double d;
  2. d = getDouble();
  3. printf("%lf\n", d);

首先,定义一个双精度浮点型变量d,用于存储getDouble函数的返回值。

然后,调用函数getDouble得到返回值,并存储在变量d中。

最后,使用函数printf输出变量d的内容。

1.3 完整代码

本案例的完整代码如下所示:

  1. #include <stdio.h>
  2. int getInt()
  3. {
  4. return 10;
  5. }
  6. double getDouble()
  7. {
  8. return 5.5;
  9. }
  10. int main()
  11. {
  12. int n;
  13. n = getInt();
  14. printf ("%d\n", n);
  15. double d;
  16. d = getDouble();
  17. printf("%lf\n", d);
  18. return 0;
  19. }

2 函数的声明

2.1 问题

定义两个函数,分别测试隐式声明和显式声明,同时体现出隐式声明中类型的自动提示效果。

2.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:函数的声明

代码如下所示:

  1. #include <stdio.h>
  2. int main()
  3. {
  4. f1();
  5. double f2(/*void*//*int i*/);
  6. f2(1,2);
  7. return 0;
  8. }
  9. int f1()
  10. {
  11. printf("f1()\n");
  12. return 0;
  13. }
  14. double f2(int a,int b)
  15. {
  16. printf("f2()\n");
  17. return 3.0;
  18. }

上述代码中,以下代码:

  1. f1();

由于在调用f1前未对其进行声明,所以是隐式声明。

上述代码中,以下代码:

  1. double f2(/*void*//*int i*/);

对函数f2进行显示声明。其中,参数可以省略。如果没有任何参数,表示可以接受任意的参数,如果写void表示不接受任何参数。

上述代码中,以下代码:

  1. f2(1,2);

调用函数f2。

上述代码中,以下代码:

  1. int f1()
  2. {
  3. printf("f1()\n");
  4. return 0;
  5. }

定义了一个函数f1。该函数没有参数,返回一个整型数据。

上述代码中,以下代码:

  1. double f2(int a,int b)
  2. {
  3. printf("f2()\n");
  4. return 3.0;
  5. }

定义了一个函数f2。该函数有两个参数,分别是整型变量a和b。在函数体中并没有使用这两个参数,这是允许的。

2.3 完整代码

本案例的完整代码如下所示:

  1. #include <stdio.h>
  2. int main()
  3. {
  4. f1();
  5. double f2(/*void*//*int i*/);
  6. f2(1,2);
  7. return 0;
  8. }
  9. int f1()
  10. {
  11. printf("f1()\n");
  12. return 0;
  13. }
  14. double f2(int a,int b)
  15. {
  16. printf("f2()\n");
  17. return 3.0;
  18. }

3 函数参数的应用

3.1 问题

定义两个函数,分别体现参数传递时的值传递和数组做参数时的处理方法。

3.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:函数参数的应用

代码如下所示:

  1. #include <stdio.h>
  2. void fun1(int a)
  3. {
  4. printf("形参a从主函数传入fun1时的值为%d\n", a);
  5. a = a + 10;
  6. printf("形参a在fun1中改变后的值为%d\n", a);
  7. }
  8. void fun2(int array[])
  9. {
  10. printf("形参array[0]从主函数传入fun2时的值为%d\n", array[0]);
  11. array[0] = array[0] + 10;
  12. printf("形参array[0]在fun2中改变后的值为%d\n", array[0]);
  13. }
  14. int main()
  15. {
  16. int a = 5;
  17. int array[10] = {1};
  18. printf("变量a在调用函数fun1之前的值为%d\n", a);
  19. fun1(a);
  20. printf("变量a在调用函数fun1之后的值为%d\n", a);
  21. printf("\n");
  22. printf("数组元素a[0]在调用函数fun2之前的值为%d\n", array[0]);
  23. fun2(array);
  24. printf("数组元素a[0]在调用函数fun2之后的值为%d\n", array[0]);
  25. return 0;
  26. }

上述代码中,以下代码:

  1. void fun1(int a)
  2. {
  3. printf("形参a从主函数传入fun1时的值为%d\n", a);
  4. a = a + 10;
  5. printf("形参a在fun1中改变后的值为%d\n", a);
  6. }

首先,定义了一个函数fun1,该函数有一个参数,为整型变量a。

然后,使用函数printf输出形参a从调用函数传入的值。

下一步,将形参a加上10。

最后,再使用函数printf输出形参a加上10后的值。两次调用可以看出形参a的变化情况。

上述代码中,以下代码:

  1. void fun2(int array[])
  2. {
  3. printf("形参array[0]从主函数传入fun2时的值为%d\n", array[0]);
  4. array[0] = array[0] + 10;
  5. printf("形参array[0]在fun2中改变后的值为%d\n", array[0]);
  6. }

首先,定义了一个函数fun1,该函数有一个参数,为整型数组array。

然后,使用函数printf输出形参数组的第一个元素array[0]从调用函数传入的值。

下一步,将形参数组的第一个元素array[0]加上10。

最后,再使用函数printf输出形参数组的第一个元素array[0]加上10后的值。两次调用可以看出形参数组的第一个元素array[0]的变化情况。

上述代码中,以下代码:

  1. int main()
  2. {
  3. int a = 5;
  4. int array[10] = {1};

在主函数中定义一个整型变量a和一个整型数组array,并将变量a初始化为5,将数组array的第一个元素初始化成1。

上述代码中,以下代码:

  1. printf("变量a在调用函数fun1之前的值为%d\n", a);
  2. fun1(a);
  3. printf("变量a在调用函数fun1之后的值为%d\n", a);

首先,使用函数printf输出变量a在调用函数fun1之前的值。

然后,调用函数fun1。

最后,再使用函数printf输出变量a在调用函数fun1之后的值。两次调用可以看出变量a的变化情况。

上述代码中,以下代码:

  1. printf("数组元素a[0]在调用函数fun2之前的值为%d\n", array[0]);
  2. fun2(array);
  3. printf("数组元素a[0]在调用函数fun2之后的值为%d\n", array[0]);

首先,使用函数printf输出整型数组array的第一个元素array[0]在调用函数fun2之前的值。

然后,调用函数fun2。

最后,再使用函数printf输出整型数组array的第一个元素array[0]在调用函数fun2之后的值。两次调用可以看出整型数组array的第一个元素array[0]的变化情况。

3.3 完整代码

本案例的完整代码如下所示:

  1. #include <stdio.h>
  2. void fun1(int a)
  3. {
  4. printf("形参a从主函数传入fun1时的值为%d\n", a);
  5. a = a + 10;
  6. printf("形参a在fun1中改变后的值为%d\n", a);
  7. }
  8. void fun2(int array[])
  9. {
  10. printf("形参array[0]从主函数传入fun2时的值为%d\n", array[0]);
  11. array[0] = array[0] + 10;
  12. printf("形参array[0]在fun2中改变后的值为%d\n", array[0]);
  13. }
  14. int main()
  15. {
  16. int a = 5;
  17. int array[10] = {1};
  18. printf("变量a在调用函数fun1之前的值为%d\n", a);
  19. fun1(a);
  20. printf("变量a在调用函数fun1之后的值为%d\n", a);
  21. printf("\n");
  22. printf("数组元素a[0]在调用函数fun2之前的值为%d\n", array[0]);
  23. fun2(array);
  24. printf("数组元素a[0]在调用函数fun2之后的值为%d\n", array[0]);
  25. return 0;
  26. }

4 函数和程序的终止

4.1 问题

定义一个函数,分别调用return语句和exit()函数,并在主函数中调用测试效果。

4.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:函数和程序的终止

代码如下所示:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. void fun(int e)
  4. {
  5. if (1 == e)
  6. exit(EXIT_SUCCESS);
  7. else
  8. return;
  9. }
  10. int main()
  11. {
  12. int n;
  13. printf("输入1在函数fun中调用exit函数\n输入2函数fun中执行return语句\n请选择输入:");
  14. scanf("%d", &n);
  15. fun(n);
  16. printf("选择2才会输出此句");
  17. return 0;
  18. }

上述代码中,以下代码:

  1. void fun(int e)
  2. {
  3. if (1 == e)
  4. exit(EXIT_SUCCESS);
  5. else
  6. return;
  7. }

定义了一个函数,该函数有一个参数为整型变量e。当参数e为1时,函数fun将调用函数exit退出程序;当参数e为其它值时,函数fun执行return语句返回。

上述代码中,以下代码:

  1. int n;
  2. printf("输入1在函数fun中调用exit函数\n输入2函数fun中执行return语句\n请选择输入:");
  3. scanf("%d", &n);

首先,定义一个整型变量n,用于存储用户输入的选择。

然后,使用函数printf提示输入选择。

最后,使用函数scanf输入一个选择到变量n中。

上述代码中,以下代码:

  1. fun(n);

将用户的选择,变量n,作为实参调用函数fun。

上述代码中,以下代码:

  1. printf("选择2才会输出此句");

当用户选择1时,程序会在函数fun中退出,则此语句将不被执行。只有用户选择了2或其他值时,函数fun将执行return语句返回,此语句才被执行。

4.3 完整代码

本案例的完整代码如下所示:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. void fun(int e)
  4. {
  5. if (1 == e)
  6. exit(EXIT_SUCCESS);
  7. else
  8. return;
  9. }
  10. int main()
  11. {
  12. int n;
  13. printf("输入1在函数fun中调用exit函数\n输入2函数fun中执行return语句\n请选择输入:");
  14. scanf("%d", &n);
  15. fun(n);
  16. printf("选择2才会输出此句\n");
  17. return 0;
  18. }

5 递归和递推的应用

5.1 问题

分别使用递归函数和循环递推的方式实现n的阶乘。

5.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:递归和递推的应用。

代码如下所示:

  1. #include <stdio.h>
  2. int factorial(int n)
  3. {
  4. if (1 == n)
  5. return 1;
  6. int f;
  7. f = n * factorial(n - 1);
  8. return f;
  9. }
  10. int main()
  11. {
  12. int n;
  13. printf("请输入求阶乘的数:");
  14. scanf("%d", &n);
  15. int f = 1;
  16. for (int i = 2; i <= n; i++)
  17. f *= i;
  18. printf("递推方法求得%d的阶乘为%d\n", n, f);
  19. f = factorial(n);
  20. printf("递归方法求得%d的阶乘为%d\n", n, f);
  21. return 0;
  22. }

上述代码中,以下代码:

  1. int factorial(int n)
  2. {
  3. if (1 == n)
  4. return 1;
  5. int f;
  6. f = n * factorial(n - 1);
  7. return f;
  8. }

定义递归函数factorial,用于计算整数n的阶乘。在该函数中,以下语句:

  1. if (1 == n)
  2. return 1;

为递归函数的出口,因为1的阶乘还是1。在该函数中,以下语句:

  1. int f;
  2. f = n * factorial(n - 1);

如果求整数n的阶乘,则转化为求n乘以n–1的阶乘,而n–1的阶乘的计算方法还是调用factorial函数,只是参数变成n-1。

上述代码中,以下代码:

  1. int main()
  2. {
  3. int n;
  4. printf("请输入求阶乘的数:");
  5. scanf("%d", &n);

首先,定义一个整型变量n,用于存储求阶乘的数。

然后,使用函数printf提示输入求阶乘的数。

最后,使用函数scanf输入求阶乘的数到变量n中。

上述代码中,以下代码:

  1. int f = 1;
  2. for (int i = 2; i <= n; i++)
  3. f *= i;
  4. printf("递推方法求得%d的阶乘为%d\n", n, f);

是使用递推的方法求整数n的阶乘,n的阶乘是计算方法为1x2x3x· · ·xN,所以使用循环逐次相乘,得到整数n的阶乘。

上述代码中,以下代码:

  1. f = factorial(n);
  2. printf("递归方法求得%d的阶乘为%d\n", n, f);

是使用递归的方法求整数n的阶乘,调用函数factorial,得到整数n的阶乘。

5.3 完整代码

本案例的完整代码如下所示:

  1. #include <stdio.h>
  2. int factorial(int n)
  3. {
  4. if (1 == n)
  5. return 1;
  6. int f;
  7. f = n * factorial(n - 1);
  8. return f;
  9. }
  10. int main()
  11. {
  12. int n;
  13. printf("请输入求阶乘的数:");
  14. scanf("%d", &n);
  15. int f = 1;
  16. for (int i = 2; i <= n; i++)
  17. f *= i;
  18. printf("递推方法求得%d的阶乘为%d\n", n, f);
  19. f = factorial(n);
  20. printf("递归方法求得%d的阶乘为%d\n", n, f);
  21. return 0;
  22. }

6 递归和递推的比较

6.1 问题

定义两个函数,分别用递归和递推方式计算费氏数列的第n项,并利用time命令查看时间差。

6.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:递归和递推的应用。

代码如下所示:

  1. #include <stdio.h>
  2. #include <time.h>
  3. long fib(int n)
  4. {
  5. long f1 = 1;
  6. long f2 = 1;
  7. long fn = 1;
  8. for (int i = 2; i < n; i++)
  9. {
  10. fn = f1 + f2;
  11. f1 = f2;
  12. f2 = fn;
  13. }
  14. return fn;
  15. }
  16. long fib_f(int n)
  17. {
  18. if (1 == n || 2 == n)
  19. return 1;
  20. return fib_f(n - 1) + fib_f(n - 2);
  21. }
  22. int main()
  23. {
  24. int n;
  25. printf("请输入月份:");
  26. scanf("%d", &n);
  27. time_t begin = time(0);
  28. long sum = fib(n);
  29. time_t stop = time(0);
  30. printf("费氏数列第%d月兔子数为%ld,递推方法用时%lf秒\n", n, sum, difftime(stop, begin));
  31. begin = time(0);
  32. sum = fib_f(n);
  33. stop = time(0);
  34. printf("费氏数列第%d月兔子数为%ld,递推方法用时%lf秒\n", n, sum, difftime(stop, begin));
  35. return 0;
  36. }

上述代码中,以下代码:

  1. long fib(int n)
  2. {
  3. long f1 = 1;
  4. long f2 = 1;
  5. long fn = 1;
  6. for (int i = 2; i < n; i++)
  7. {
  8. fn = f1 + f2;
  9. f1 = f2;
  10. f2 = fn;
  11. }
  12. return fn;
  13. }

定义了一个使用递推的方法求费氏数列的函数fib,该函数有一个参数是要求第几个月的兔子数。费氏数列的计算公式为:

f1 = 1

f2 = 1

fn = fn-1 + fn-2

上述代码中,以下代码:

  1. fn = f1 + f2;

按计算公式fn = fn-1 + fn-2计算。

上述代码中,以下代码:

  1. f1 = f2;
  2. f2 = fn;

为下一次循环中公式fn = fn-1 + fn-2中的f1和f2做准备。

上述代码中,以下代码:

  1. long fib_f(int n)
  2. {
  3. if (1 == n || 2 == n)
  4. return 1;
  5. return fib_f(n - 1) + fib_f(n - 2);
  6. }

定义了一个使用递归的方法求费氏数列的函数fib_f,该函数有一个参数是要求第几个月的兔子数。该函数中,以下代码:

  1. if (1 == n || 2 == n)
  2. return 1;

为递归出口,根据公式,第1个月和第2个月的兔子数均为1。该函数中,以下代码:

  1. return fib_f(n - 1) + fib_f(n - 2);

根据公式fn = fn-1 + fn-2求第n个月的兔子数,因为求第n-1个月和第n-2个月与求第n个月的兔子数方法相同,都是调用fib_f函数,只是参数不同罢了,所以使用递归方法。

上述代码中,以下代码:

  1. int main()
  2. {
  3. int n;
  4. printf("请输入月份:");
  5. scanf("%d", &n);

首先,定义一个整型变量n,用于存储求兔子数的月份数。

然后,使用函数printf提示输入求兔子数的月份数。

最后,使用函数scanf输入求兔子数的月份数到变量n中。

上述代码中,以下代码:

  1. time_t begin = time(0);
  2. long sum = fib(n);
  3. time_t stop = time(0);
  4. printf("费氏数列第%d月兔子数为%ld,递推方法用时%lf秒\n", n, sum, difftime(stop, begin));

首先,使用time函数记录调用递推方法函数fib开始的时间。

然后,调用函数fib计算输入月份的兔子数。

下一步,使用time函数记录调用递推方法函数fib结束的时间。

最后,打印输入月份的兔子数和计算所用的时间数。

上述代码中,以下代码:

  1. begin = time(0);
  2. sum = fib_f(n);
  3. stop = time(0);
  4. printf("费氏数列第%d月兔子数为%ld,递推方法用时%lf秒\n", n, sum, difftime(stop, begin));

首先,使用time函数记录调用递归方法函数fib_f开始的时间。

然后,调用函数fib_f计算输入月份的兔子数。

下一步,使用time函数记录调用递归方法函数fib_f结束的时间。

最后,打印输入月份的兔子数和计算所用的时间数。

6.3 完整代码

本案例的完整代码如下所示:

  1. #include <stdio.h>
  2. #include <time.h>
  3. long fib(int n)
  4. {
  5. long f1 = 1;
  6. long f2 = 1;
  7. long fn = 1;
  8. for (int i = 2; i < n; i++)
  9. {
  10. fn = f1 + f2;
  11. f1 = f2;
  12. f2 = fn;
  13. }
  14. return fn;
  15. }
  16. long fib_f(int n)
  17. {
  18. if (1 == n || 2 == n)
  19. return 1;
  20. return fib_f(n - 1) + fib_f(n - 2);
  21. }
  22. int main()
  23. {
  24. int n;
  25. printf("请输入月份:");
  26. scanf("%d", &n);
  27. time_t begin = time(0);
  28. long sum = fib(n);
  29. time_t stop = time(0);
  30. printf("费氏数列第%d月兔子数为%ld,递推方法用时%lf秒\n", n, sum, difftime(stop, begin));
  31. begin = time(0);
  32. sum = fib_f(n);
  33. stop = time(0);
  34. printf("费氏数列第%d月兔子数为%ld,递推方法用时%lf秒\n", n, sum, difftime(stop, begin));
  35. return 0;
  36. }

7 递归的典型应用

7.1 问题

使用递归实现汉诺塔。

汉诺塔是指法国数学家爱德华·卢卡斯曾编写过一个印度的古老传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔。不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在哪根针上,小片必须在大片上面。僧侣们预言,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而梵塔、庙宇和众生也都将同归于尽。

7.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:递归的典型应用。

代码如下所示:

  1. #include <stdio.h>
  2. void move(int n,char a,char b,char c)
  3. {
  4. if(n==1)
  5. printf("\t%c->%c\n",a,c);
  6. else
  7. {
  8. move(n-1,a,c,b);
  9. printf("\t%c->%c\n",a,c);
  10. move(n-1,b,a,c);
  11. }
  12. }
  13. int main()
  14. {
  15. int n;
  16. printf("请输入要移动的块数:");
  17. scanf("%d",&n);
  18. move(n,‘a‘,‘b‘,‘c‘);
  19. return 0;
  20. }

上述代码中,以下代码:

  1. void move(int n,char a,char b,char c)
  2. {
  3. if(n==1)
  4. printf("\t%c->%c\n",a,c);
  5. else
  6. {
  7. move(n-1,a,c,b);
  8. printf("\t%c->%c\n",a,c);
  9. move(n-1,b,a,c);
  10. }
  11. }

定义了一个递归函数move,用来模拟移动盘子。该函数有四个参数,说明如下:

第一个参数为盘子的数量。

第二个参数为从这根针移走。

第三个参数为经过这根针。

第四个参数为移到这根针。

在该函数中,以下代码:

  1. if(n==1)
  2. printf("\t%c->%c\n",a,c);

表示当n只有1个盘子的时候直接从a移动到c。

在该函数中,以下代码:

  1. move(n-1,a,c,b);

表示第n-1个盘子要从a通过c移动到b。

在该函数中,以下代码:

  1. printf("\t%c->%c\n",a,c);

输出从a移动到c。

在该函数中,以下代码:

  1. move(n-1,b,a,c);

表示n-1个盘子移动到b后,b变开始盘,b通过a移动到c。

上述代码中,以下代码:

  1. int main()
  2. {
  3. int n;
  4. printf("请输入要移动的块数:");
  5. scanf("%d",&n);

首先,定义一个整型变量n,用于存储要移动的盘子数。

然后,使用函数printf提示输入要移动的盘子数。

最后,使用函数scanf输入要移动的盘子数到变量n中。

上述代码中,以下代码:

  1. move(n,‘a‘,‘b‘,‘c‘);

启动移动函数,输出移动过程。

7.3 完整代码

本案例的完整代码如下所示:

  1. #include <stdio.h>
  2. void move(int n,char a,char b,char c)
  3. {
  4. if(n==1)
  5. printf("\t%c->%c\n",a,c); //当n只有1个的时候直接从a移动到c
  6. else
  7. {
  8. move(n-1,a,c,b); //第n-1个要从a通过c移动到b
  9. printf("\t%c->%c\n",a,c);
  10. move(n-1,b,a,c); //n-1个移动过来之后b变开始盘,b通过a移动到c,这边很难理解
  11. }
  12. }
  13. int main()
  14. {
  15. int n;
  16. printf("请输入要移动的块数:");
  17. scanf("%d",&n);
  18. move(n,‘a‘,‘b‘,‘c‘);
  19. return 0;
  20. }

标准函数库

1 格式化输入输出

1.1 问题

测试格式化输入输出函数的中格式字符串的各种效果。

1.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:格式化输入输出

代码如下所示:

  1. #include <stdio.h>
  2. int main()
  3. {
  4. int a = 0, b = 0;
  5. scanf("%*d%d", &a, &b);
  6. printf("a = %d, b = %d\n", a, b);
  7. printf("%10d,%-10d,%d\n", 100, 200, 300);
  8. printf("%08d\n", 100);
  9. printf("%0*d\n", 8, 100);
  10. printf("0%o,0x%x\n", 8, 16);
  11. printf("%.2f\n", 12.34567);
  12. printf("%10.2f\n", 12.34567);
  13. return 0;
  14. }

上述代码中,以下代码:

  1. scanf("%*d%d", &a, &b);

%*d中的*表示禁止字符,即输入的第一个数据被跳过,不进行赋值。

上述代码中,以下代码:

  1. printf("%10d,%-10d,%d\n", 100, 200, 300);

首先,%10d中的10表示该数据如果不足10位则左边补空格。

然后,%-10d中的-10表示该数据如果不足10位则右边补空格。

上述代码中,以下代码:

  1. printf("%08d\n", 100);

%08d中的08表示数据如果不足8位则左边补0。

上述代码中,以下代码:

  1. printf("%0*d\n", 8, 100);

%0*d中的0*表示数据不足后面第一个参数,即8,所含的位数,则左边补0。

上述代码中,以下代码:

  1. printf("0%o,0x%x\n", 8, 16);

0%o表示将数据按8进制输出;0x%x表示将数据按16进制输出。

上述代码中,以下代码:

  1. printf("%.2f\n", 12.34567);

%.2f表示将数据保留2位小数。

上述代码中,以下代码:

  1. printf("%10.2f\n", 12.34567);

%10.2表示将数据保留2位小数,且包括小数点在内的位数不足10位时,左边补0。

1.3 完整代码

本案例的完整代码如下所示:

  1. #include <stdio.h>
  2. int main()
  3. {
  4. int a = 0, b = 0;
  5. scanf("%*d%d", &a, &b);
  6. printf("a = %d, b = %d\n", a, b);
  7. printf("%10d,%-10d,%d\n", 100, 200, 300);
  8. printf("%08d\n", 100);
  9. printf("%0*d\n", 8, 100);
  10. printf("0%o,0x%x\n", 8, 16);
  11. printf("%.2f\n", 12.34567);
  12. printf("%10.2f\n", 12.34567);
  13. return 0;
  14. }

2 动态分配内存

2.1 问题

动态分配基本类型和字符串的内存,并进行数据存储和取出打印。(最后记得用free()释放)

2.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:动态分配内存

代码如下所示:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. int main()
  5. {
  6. int *pi = (int*)malloc(sizeof(int));
  7. *pi = 10;
  8. printf("*pi = %d\n", *pi);
  9. free(pi);
  10. float *pf = (float*)malloc(sizeof(float));
  11. *pf = 10.23;
  12. printf("*pf = %f\n", *pf);
  13. free(pf);
  14. double *pd = (double*)malloc(sizeof(double));
  15. *pd = 123.456;
  16. printf("*pd = %lf\n", *pd);
  17. free(pd);
  18. char *pstr = (char*)malloc(1024);
  19. strcpy(pstr, "将字符串放在堆上");
  20. printf("%s\n", pstr);
  21. free(pstr);
  22. return 0;
  23. }

上述代码中,以下代码:

  1. int *pi = (int*)malloc(sizeof(int));

在堆上动态分配一个整型变量。

上述代码中,以下代码:

  1. *pi = 10;

将动态分配的整型变量赋值。

上述代码中,以下代码:

  1. printf("*pi = %d\n", *pi);

使用printf函数输出动态变量的值。

上述代码中,以下代码:

  1. free(pi);

释放动态变量所占的存储空间。

上述代码中,以下代码:

  1. float *pf = (float*)malloc(sizeof(float));

在堆上动态分配一个单精度浮点型变量。

上述代码中,以下代码:

  1. *pf = 10.23;

将动态分配的单精度浮点型变量赋值。

上述代码中,以下代码:

  1. printf("*pf = %f\n", *pf);

使用printf函数输出动态变量的值。

上述代码中,以下代码:

  1. free(pf);

释放动态变量所占的存储空间。

上述代码中,以下代码:

  1. double *pd = (double*)malloc(sizeof(double));

在堆上动态分配一个双精度浮点型变量。

上述代码中,以下代码:

  1. *pd = 123.456;

将动态分配的双精度浮点型变量赋值。

上述代码中,以下代码:

  1. printf("*pd = %lf\n", *pd);

使用printf函数输出动态变量的值。

上述代码中,以下代码:

  1. free(pd);

释放动态变量所占的存储空间。

上述代码中,以下代码:

  1. char *pstr = (char*)malloc(1024);

在堆上动态分配一个字符型数组。

上述代码中,以下代码:

  1. strcpy(pstr, "将字符串放在堆上");

将字符型数组赋值为字符串。

上述代码中,以下代码:

  1. printf("%s\n", pstr);

使用printf函数输出动态字符型数组。

上述代码中,以下代码:

  1. free(pstr);

释放动态字符型数组所占的存储空间。

2.3 完整代码

本案例的完整代码如下所示:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. int main()
  5. {
  6. int *pi = (int*)malloc(sizeof(int));
  7. *pi = 10;
  8. printf("*pi = %d\n", *pi);
  9. free(pi);
  10. float *pf = (float*)malloc(sizeof(float));
  11. *pf = 10.23;
  12. printf("*pf = %f\n", *pf);
  13. free(pf);
  14. double *pd = (double*)malloc(sizeof(double));
  15. *pd = 123.456;
  16. printf("*pd = %lf\n", *pd);
  17. free(pd);
  18. char *pstr = (char*)malloc(1024);
  19. strcpy(pstr, "将字符串放在堆上");
  20. printf("%s\n", pstr);
  21. free(pstr);
  22. return 0;
  23. }

3 动态分配内存(续1)

3.1 问题

动态分配整型数组和结构的内存,并进行数据存储和取出打印。(最后记得用free()释放)

3.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:动态分配内存(续1)

代码如下所示:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main()
  4. {
  5. int *array = (int *)malloc(sizeof(int) * 10);
  6. for (int i = 0; i < 10; i++)
  7. array[i] = i + 1;
  8. for (int i = 0; i < 10; i++)
  9. printf("%d ", array[i]);
  10. printf("\n");
  11. free(array);
  12. struct Data
  13. {
  14. int a;
  15. double b;
  16. char c;
  17. };
  18. struct Data *p = (struct Data*)malloc(sizeof(struct Data));
  19. p->a = 10;
  20. p->b = 12.34;
  21. p->c = ‘a‘;
  22. printf("%d %lf %c\n", p->a, p->b, p->c);
  23. free(p);
  24. return 0;
  25. }

上述代码中,以下代码:

  1. int *array = (int *)malloc(sizeof(int) * 10);

在堆上定义了一个整型数组。该数组共有10个元素。

上述代码中,以下代码:

  1. for (int i = 0; i < 10; i++)
  2. array[i] = i + 1;

使用循环对堆上的数组元素进行逐个赋值。

上述代码中,以下代码:

  1. for (int i = 0; i < 10; i++)
  2. printf("%d ", array[i]);
  3. printf("\n");

使用循环遍历输出堆上的数组中的所有元素。

上述代码中,以下代码:

  1. free(array);

释放堆上的整型数组。

上述代码中,以下代码:

  1. struct Data
  2. {
  3. int a;
  4. double b;
  5. char c;
  6. };

定义一个结构体Data,有三个成员,整型变量a,双精度浮点型变量b,字符型变量c。

上述代码中,以下代码:

  1. struct Data *p = (struct Data*)malloc(sizeof(struct Data));

在堆上动态分配一个结构体Data的变量。

上述代码中,以下代码:

  1. p->a = 10;
  2. p->b = 12.34;
  3. p->c = ‘a‘;

対堆上的结构体变量的每个成员进行赋值。

上述代码中,以下代码:

  1. printf("%d %lf %c\n", p->a, p->b, p->c);

使用printf函数输出堆上的结构体Data的变量。

上述代码中,以下代码:

  1. free(p);

释放堆上的结构体Data的变量。

3.3 完整代码

本案例的完整代码如下所示:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main()
  4. {
  5. int *array = (int *)malloc(sizeof(int) * 10);
  6. for (int i = 0; i < 10; i++)
  7. array[i] = i + 1;
  8. for (int i = 0; i < 10; i++)
  9. printf("%d ", array[i]);
  10. printf("\n");
  11. free(array);
  12. struct Data
  13. {
  14. int a;
  15. double b;
  16. char c;
  17. };
  18. struct Data *p = (struct Data*)malloc(sizeof(struct Data));
  19. p->a = 10;
  20. p->b = 12.34;
  21. p->c = ‘a‘;
  22. printf("%d %lf %c\n", p->a, p->b, p->c);
  23. free(p);
  24. return 0;
  25. }

4 时间函数的使用

4.1 问题

打印年月日小时分秒格式的系统当前时间。

4.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:时间函数的使用

代码如下所示:

  1. #include <stdio.h>
  2. #include <time.h>
  3. int main()
  4. {
  5. time_t t = time(0);
  6. struct tm * local = localtime(&t);
  7. printf("%d年%d月%d日 %d:%d:%d\n", 1900 + local->tm_year, local->tm_mon + 1, local->tm_mday, local->tm_hour, local->tm_min, local->tm_sec);
  8. return 0;
  9. }

上述代码中,以下代码:

  1. time_t t = time(0);

使用函数time获取当前系统时间。

上述代码中,以下代码:

  1. struct tm * local = localtime(&t);

将系统时间转换成本地时间。

上述代码中,以下代码:

  1. printf("%d年%d月%d日 %d:%d:%d\n", 1900 + local->tm_year, local->tm_mon + 1, local->tm_mday, local->tm_hour, local->tm_min, local->tm_sec);

使用printf函数输出本地时间。

4.3 完整代码

本案例的完整代码如下所示:

  1. #include <stdio.h>
  2. #include <time.h>
  3. int main()
  4. {
  5. time_t t = time(0);
  6. struct tm * local = localtime(&t);
  7. printf("%d年%d月%d日 %d:%d:%d\n", 1900 + local->tm_year, local->tm_mon + 1, local->tm_mday, local->tm_hour, local->tm_min, local->tm_sec);
  8. return 0;
  9. }

输入输出函数(IO)

1 打开文件

1.1 问题

用各种模式打开文件。

1.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:格式化输入输出

代码如下所示:

  1. #include <stdio.h>
  2. int main(void)
  3. {
  4. FILE*fp=NULL;
  5. fp=fopen("file.c","w");
  6. if(NULL==fp)
  7. {
  8. return -1;
  9. }
  10. fclose(fp);
  11. fp=NULL;
  12. fp=fopen("file.c","a");
  13. if(NULL==fp)
  14. {
  15. return -1;
  16. }
  17. fclose(fp);
  18. fp=NULL;
  19. fp=fopen("file.c","r");
  20. if(NULL==fp)
  21. {
  22. return -1;
  23. }
  24. fclose(fp);
  25. fp=NULL;
  26. return 0;
  27. }

上述代码中,以下代码:

  1. FILE*fp=NULL;

定义一个FILE类型的指针fp。

上述代码中,以下代码:

  1. fp=fopen("file.c","w");
  2. if(NULL==fp)
  3. {
  4. return -1;
  5. }
  6. fclose(fp);
  7. fp=NULL;

首先,使用函数fopen打开一个文件,该函数有两个参数,说明如下:

第一个参数为字符串包含欲打开的文件路径及文件名。

第二个参数为字符串代表文件打开方式。

在上述语句中,打开的文件名为当前目录下的file.c。使用w方式打开,该方式打开只写文件,若文件存在则清空原文件,若不存在新建。

然后,使用函数fclose关闭打开的文件。

上述代码中,以下代码:

  1. fp=fopen("file.c","a");
  2. if(NULL==fp)
  3. {
  4. return -1;
  5. }
  6. fclose(fp);
  7. fp=NULL;

首先,使用函数fopen打开一个文件。

在上述语句中,打开的文件名为当前目录下的file.c。使用a方式打开,该方式以追加的方式打开只写文件,若文件存在则在最后追加写入,若不存在新建。

然后,使用函数fclose关闭打开的文件。

上述代码中,以下代码:

  1. fp=fopen("file.c","r");
  2. if(NULL==fp)
  3. {
  4. return -1;
  5. }
  6. fclose(fp);
  7. fp=NULL;

首先,使用函数fopen打开一个文件。

在上述语句中,打开的文件名为当前目录下的file.c。使用r方式打开,该方式打开只读文件,该文件必须存在。

然后,使用函数fclose关闭打开的文件。

1.3 完整代码

本案例的完整代码如下所示:

  1. #include <stdio.h>
  2. int main(void)
  3. {
  4. FILE*fp=NULL;
  5. fp=fopen("file.c","w");
  6. if(NULL==fp)
  7. {
  8. return -1;
  9. }
  10. fclose(fp);
  11. fp=NULL;
  12. fp=fopen("file.c","a");
  13. if(NULL==fp)
  14. {
  15. return -1;
  16. }
  17. fclose(fp);
  18. fp=NULL;
  19. fp=fopen("file.c","r");
  20. if(NULL==fp)
  21. {
  22. return -1;
  23. }
  24. fclose(fp);
  25. fp=NULL;
  26. return 0;
  27. }

2 使用fscanf()和fprintf()读写文件

2.1 问题

fscanf函数的功能是从一个流中执行格式化输入,fscanf遇到空格和换行时结束。

fprintf函数的功能是传送格式化输出到一个文件中。

2.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:使用fscanf()和fprintf()读写文件

代码如下所示:

  1. #include <stdio.h>
  2. int main(void)
  3. {
  4. FILE*fp=NULL;
  5. fp=fopen("file.c","w");
  6. if(NULL==fp)
  7. {
  8. return -1;
  9. }
  10. int a = 10;
  11. float f = 12.34;
  12. double d = 12345.6789;
  13. char c = ‘a‘;
  14. fprintf(fp, "%c %d %f %lf", c, a, f, d);
  15. fclose(fp);
  16. fp=NULL;
  17. fp=fopen("file.c","r");
  18. if(NULL==fp)
  19. {
  20. return -1;
  21. }
  22. char c1;
  23. int a1;
  24. float f1;
  25. double d1;
  26. fscanf(fp, "%c%d%f%lf", &c1, &a1, &f1, &d1);
  27. printf("%c\n%d\n%f\n%lf\n", c1, a1, f1, d1);
  28. fclose(fp);
  29. fp=NULL;
  30. return 0;
  31. }

上述代码中,以下代码:

  1. FILE*fp=NULL;

定义一个FILE类型的指针fp。

上述代码中,以下代码:

  1. fp=fopen("file.c","w");
  2. if(NULL==fp)
  3. {
  4. return -1;
  5. }

使用函数fopen用w的方式打开一个文件file.c。

上述代码中,以下代码:

  1. int a = 10;
  2. float f = 12.34;
  3. double d = 12345.6789;
  4. char c = ‘a‘;

定义四个变量,并对它们进行初始化。

上述代码中,以下代码:

  1. fprintf(fp, "%c %d %f %lf", c, a, f, d);

使用函数fprintf用格式化方法将上述四个变量写入文件中。该函数与printf使用方法非常类似。

上述代码中,以下代码:

  1. float *pf = (float*)malloc(sizeof(float));

在堆上动态分配一个单精度浮点型变量。

上述代码中,以下代码:

  1. fclose(fp);
  2. fp=NULL;

使用函数fclose关闭打开的文件。

上述代码中,以下代码:

  1. fp=fopen("file.c","r");
  2. if(NULL==fp)
  3. {
  4. return -1;
  5. }

首先,使用函数fopen用r的方式重新打开文件file.c。

上述代码中,以下代码:

  1. char c1;
  2. int a1;
  3. float f1;
  4. double d1;

重新定义四个新的变量,但并不对它们进行初始化。

上述代码中,以下代码:

  1. fscanf(fp, "%c%d%f%lf", &c1, &a1, &f1, &d1);

使用函数fscanf用格式化方法从文件file.c中读入数据到这四个新的变量中。该函数与scanf使用方法非常类似。

上述代码中,以下代码:

  1. printf("%c\n%d\n%f\n%lf\n", c1, a1, f1, d1);

使用函数printf输出这四个新的变量值,已验证读入的效果。

上述代码中,以下代码:

  1. fclose(fp);
  2. fp=NULL;

使用函数fclose关闭打开的文件。

2.3 完整代码

本案例的完整代码如下所示:

  1. #include <stdio.h>
  2. int main(void)
  3. {
  4. FILE*fp=NULL;
  5. fp=fopen("file.c","w");
  6. if(NULL==fp)
  7. {
  8. return -1;
  9. }
  10. int a = 10;
  11. float f = 12.34;
  12. double d = 12345.6789;
  13. char c = ‘a‘;
  14. fprintf(fp, "%c %d %f %lf", c, a, f, d);
  15. fclose(fp);
  16. fp=NULL;
  17. fp=fopen("file.c","r");
  18. if(NULL==fp)
  19. {
  20. return -1;
  21. }
  22. char c1;
  23. int a1;
  24. float f1;
  25. double d1;
  26. fscanf(fp, "%c%d%f%lf", &c1, &a1, &f1, &d1);
  27. printf("%c\n%d\n%f\n%lf\n", c1, a1, f1, d1);
  28. fclose(fp);
  29. fp=NULL;
  30. return 0;
  31. }

3 使用fread()和fwrite()读写文件

3.1 问题

使用fwrite()和fread()读写int、double、字符串类型的数据,先写入后读取。

3.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:使用fread()和fwrite()读写文件

代码如下所示:

  1. #include <stdio.h>
  2. #include <string.h>
  3. int main(void)
  4. {
  5. FILE*fp=NULL;
  6. fp=fopen("file.c","w");
  7. if(NULL==fp)
  8. {
  9. return -1;
  10. }
  11. int a = 10;
  12. double d = 12345.6789;
  13. char str[1024] = "This is a string.";
  14. fwrite(&a, sizeof(int), 1, fp);
  15. fwrite(&d, sizeof(double), 1, fp);
  16. int len = strlen(str) + 1;
  17. fwrite(&len, sizeof(int), 1, fp);
  18. fwrite(str, sizeof(char), len, fp);
  19. fclose(fp);
  20. fp=NULL;
  21. fp=fopen("file.c","r");
  22. if(NULL==fp)
  23. {
  24. return -1;
  25. }
  26. int a1;
  27. double d1;
  28. char str1[1024];
  29. fread(&a1, sizeof(int), 1, fp);
  30. fread(&d1, sizeof(double), 1, fp);
  31. int len1;
  32. fread(&len1, sizeof(int), 1, fp);
  33. fread(str1, sizeof(char), len, fp);
  34. printf("%d\n%lf\n%s\n", a1, d1, str1);
  35. fclose(fp);
  36. fp=NULL;
  37. return 0;
  38. }

上述代码中,以下代码:

  1. FILE*fp=NULL;

定义一个FILE类型的指针fp。

上述代码中,以下代码:

  1. fp=fopen("file.c","w");
  2. if(NULL==fp)
  3. {
  4. return -1;
  5. }

使用函数fopen用w的方式打开一个文件file.c。

上述代码中,以下代码:

  1. int a = 10;
  2. double d = 12345.6789;
  3. char str[1024] = "This is a string.";

定义两个变量和一个数组,并对它们进行初始化。

上述代码中,以下代码:

  1. fwrite(&a, sizeof(int), 1, fp);

使用fwrite函数将变量a写入文件。该函数有四个参数,说明如下:

第一个参数为是一个指针,是要获取写入文件的数据的地址。

第二个参数为要写入内容的单字节数。

第三个参数为要进行写入第二个参数中字节的数据项的个数。

第四个参数为目标文件指针。

上述代码中,以下代码:

  1. fwrite(&d, sizeof(double), 1, fp);

使用fwrite函数将变量d写入文件。

上述代码中,以下代码:

  1. int len = strlen(str) + 1;
  2. fwrite(&len, sizeof(int), 1, fp);
  3. fwrite(str, sizeof(char), len, fp);

使用fwrite函数将字符数组str写入文件。写入字符数组时,应先将该数组中字符串的长度存入文件,再存入字符串本身,这样有理由读文件时,定义读取字符串的长度。

上述代码中,以下代码:

  1. fclose(fp);
  2. fp=NULL;

使用函数fclose关闭打开的文件。

上述代码中,以下代码:

  1. fp=fopen("file.c","r");
  2. if(NULL==fp)
  3. {
  4. return -1;
  5. }

使用函数fopen用r的方式重新打开文件file.c。

上述代码中,以下代码:

  1. int a1;
  2. double d1;
  3. char str1[1024];

重新定义两个变量和一个数组,但并不对它们进行初始化。

上述代码中,以下代码:

  1. fread(&a1, sizeof(int), 1, fp);

使用fread函数从文件中读入数据放在变量a1中。该函数有四个参数,说明如下:

第一个参数为是一个指针,是要将获取的数据写入到的地址。

第二个参数为要读取内容的单字节数。

第三个参数为要进行读取第二个参数中字节的数据项的个数。

第四个参数为目标文件指针。

上述代码中,以下代码:

  1. fread(&d1, sizeof(double), 1, fp);

使用fread函数从文件中读入数据放在变量d1中。

上述代码中,以下代码:

  1. int len1;
  2. fread(&len1, sizeof(int), 1, fp);
  3. fread(str1, sizeof(char), len, fp);

使用fread函数从文件中读入数据放在字符数组str中。在读取字符串前,先读取该字符串的长度,然后根据长度读取字符串的内容。

上述代码中,以下代码:

  1. printf("%d\n%lf\n%s\n", a1, d1, str1);

使用printf函数验证读取的内容是否正确。

上述代码中,以下代码:

  1. fclose(fp);
  2. fp=NULL;

使用函数fclose关闭打开的文件。

3.3 完整代码

本案例的完整代码如下所示:

  1. #include <stdio.h>
  2. #include <string.h>
  3. int main(void)
  4. {
  5. FILE*fp=NULL;
  6. fp=fopen("file.c","w");
  7. if(NULL==fp)
  8. {
  9. return -1;
  10. }
  11. int a = 10;
  12. double d = 12345.6789;
  13. char str[1024] = "This is a string.";
  14. fwrite(&a, sizeof(int), 1, fp);
  15. fwrite(&d, sizeof(double), 1, fp);
  16. int len = strlen(str) + 1;
  17. fwrite(&len, sizeof(int), 1, fp);
  18. fwrite(str, sizeof(char), len, fp);
  19. fclose(fp);
  20. fp=NULL;
  21. fp=fopen("file.c","r");
  22. if(NULL==fp)
  23. {
  24. return -1;
  25. }
  26. int a1;
  27. double d1;
  28. char str1[1024];
  29. fread(&a1, sizeof(int), 1, fp);
  30. fread(&d1, sizeof(double), 1, fp);
  31. int len1;
  32. fread(&len1, sizeof(int), 1, fp);
  33. fread(str1, sizeof(char), len, fp);
  34. printf("%d\n%lf\n%s\n", a1, d1, str1);
  35. fclose(fp);
  36. fp=NULL;
  37. return 0;
  38. }

4 使用fread()和fwrite()读写文件(续1)

4.1 问题

输入学生信息(学号、姓名、出生日期),然后用结构存储数据,并读写入文件中。

4.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:使用fread()和fwrite()读写文件(续1)

代码如下所示:

  1. #include <stdio.h>
  2. #include <string.h>
  3. struct student
  4. {
  5. int id;
  6. char name[20];
  7. char address[200];
  8. };
  9. int main(void)
  10. {
  11. FILE*fp=NULL;
  12. fp=fopen("file.c","w");
  13. if(NULL==fp)
  14. {
  15. return -1;
  16. }
  17. struct student stu = {10000, "zhangsan", "江苏南京"};
  18. fwrite(&stu, sizeof(struct student), 1, fp);
  19. fclose(fp);
  20. fp=NULL;
  21. fp=fopen("file.c","r");
  22. if(NULL==fp)
  23. {
  24. return -1;
  25. }
  26. struct student stu1;
  27. fread(&stu1, sizeof(struct student), 1, fp);
  28. printf("%d %s %s\n", stu1.id, stu1.name, stu1.address);
  29. fclose(fp);
  30. fp=NULL;
  31. return 0;
  32. }

上述代码中,以下代码:

  1. FILE*fp=NULL;

定义一个FILE类型的指针fp。

上述代码中,以下代码:

  1. fp=fopen("file.c","w");
  2. if(NULL==fp)
  3. {
  4. return -1;
  5. }

使用函数fopen用w的方式打开一个文件file.c。

上述代码中,以下代码:

  1. struct student stu = {10000, "zhangsan", "江苏南京"};

定义一个结构体student的变量stu,并对它进行初始化。

上述代码中,以下代码:

  1. fwrite(&stu, sizeof(struct student), 1, fp);

使用fwrite函数将结构体student的变量stu写入文件。

上述代码中,以下代码:

  1. fclose(fp);
  2. fp=NULL;

使用函数fclose关闭打开的文件。

上述代码中,以下代码:

  1. fp=fopen("file.c","r");
  2. if(NULL==fp)
  3. {
  4. return -1;
  5. }

使用函数fopen用r的方式重新打开文件file.c。

上述代码中,以下代码:

  1. struct student stu1;

重新定义一个结构体student的变量stu1,但并不对它进行初始化。

上述代码中,以下代码:

  1. fread(&stu1, sizeof(struct student), 1, fp);

使用fread函数从文件中读入数据放在结构体student的变量stu1中。

上述代码中,以下代码:

  1. printf("%d %s %s\n", stu1.id, stu1.name, stu1.address);

使用printf函数验证读取的内容是否正确。

上述代码中,以下代码:

  1. fclose(fp);
  2. fp=NULL;

使用函数fclose关闭打开的文件。

4.3 完整代码

本案例的完整代码如下所示:

  1. #include <stdio.h>
  2. #include <string.h>
  3. struct student
  4. {
  5. int id;
  6. char name[20];
  7. char address[200];
  8. };
  9. int main(void)
  10. {
  11. FILE*fp=NULL;
  12. fp=fopen("file.c","w");
  13. if(NULL==fp)
  14. {
  15. return -1;
  16. }
  17. struct student stu = {10000, "zhangsan", "江苏南京"};
  18. fwrite(&stu, sizeof(struct student), 1, fp);
  19. fclose(fp);
  20. fp=NULL;
  21. fp=fopen("file.c","r");
  22. if(NULL==fp)
  23. {
  24. return -1;
  25. }
  26. struct student stu1;
  27. fread(&stu1, sizeof(struct student), 1, fp);
  28. printf("%d %s %s\n", stu1.id, stu1.name, stu1.address);
  29. fclose(fp);
  30. fp=NULL;
  31. return 0;
  32. }

5 fseek()的使用

5.1 问题

测试fseek()的效果,包括三个不同的起始位置。

5.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:fseek()的使用

代码如下所示:

  1. #include <stdio.h>
  2. #include <string.h>
  3. int main(void)
  4. {
  5. FILE*fp=NULL;
  6. fp=fopen("file.c","w+");
  7. if(NULL==fp)
  8. {
  9. return -1;
  10. }
  11. char buf[] = "abcdefghijklmnopqrstuvwxyz";
  12. fwrite(buf, sizeof(char), 26, fp);
  13. fseek(fp, 0, SEEK_SET);
  14. memset(buf, 0, 26);
  15. fread(buf, sizeof(char), 10, fp);
  16. printf("%s\n", buf);
  17. fseek(fp, 5, SEEK_CUR);
  18. memset(buf, 0, 26);
  19. fread(buf, sizeof(char), 10, fp);
  20. printf("%s\n", buf);
  21. fseek(fp, -10, SEEK_END);
  22. memset(buf, 0, 26);
  23. fread(buf, sizeof(char), 10, fp);
  24. printf("%s\n", buf);
  25. fclose(fp);
  26. fp=NULL;
  27. return 0;
  28. }

上述代码中,以下代码:

  1. FILE*fp=NULL;

定义一个FILE类型的指针fp。

上述代码中,以下代码:

  1. fp=fopen("file.c","w+");
  2. if(NULL==fp)
  3. {
  4. return -1;
  5. }

使用函数fopen用w+的方式打开一个文件file.c。

上述代码中,以下代码:

  1. char buf[] = "abcdefghijklmnopqrstuvwxyz";

定义一个字符数组buf,并初始化为一个字符串。

上述代码中,以下代码:

  1. fwrite(buf, sizeof(char), 26, fp);

使用fwrite函数将字符串buf写入文件。

上述代码中,以下代码:

  1. fseek(fp, 0, SEEK_SET);
  2. memset(buf, 0, 26);
  3. fread(buf, sizeof(char), 10, fp);
  4. printf("%s\n", buf);

首先,使用函数fseek设置文件指针fp的位置为文件头开始的第一个字节。该函数有三个参数,说明如下:

第一个参数为目标文件指针。

第二个参数为从第三个参数开始的偏移量,为正数时向后偏移,为负数时向前偏移。

第三个参数为偏移的起始位置。

然后,使用memset函数将字符串buf清空。

下一步,使用fread函数从文件当前设定位置读入10个字符。

最后,使用printf函数验证读入的字符是从文件开头第一个字节开始的10个字符。

上述代码中,以下代码:

  1. fseek(fp, 5, SEEK_CUR);
  2. memset(buf, 0, 26);
  3. fread(buf, sizeof(char), 10, fp);
  4. printf("%s\n", buf);

首先,使用函数fseek设置文件指针fp的位置为文件当前位置向后偏移5个字节的位置。

然后,使用memset函数将字符串buf清空。

下一步,使用fread函数从文件当前设定位置读入10个字符。

最后,使用printf函数验证读入的字符是从文件当前位置向后偏移5个字节开始的10个字符。

上述代码中,以下代码:

  1. fseek(fp, -10, SEEK_END);
  2. memset(buf, 0, 26);
  3. fread(buf, sizeof(char), 10, fp);
  4. printf("%s\n", buf);

首先,使用函数fseek设置文件指针fp的位置为文件尾开始向前偏移10个字节的位置。

然后,使用memset函数将字符串buf清空。

下一步,使用fread函数从文件当前设定位置读入10个字符。

最后,使用printf函数验证读入的字符是从文件尾开始向前偏移10个字节开始的10个字符。

上述代码中,以下代码:

  1. fclose(fp);
  2. fp=NULL;

使用函数fclose关闭打开的文件。

5.3 完整代码

本案例的完整代码如下所示:

  1. #include <stdio.h>
  2. #include <string.h>
  3. int main(void)
  4. {
  5. FILE*fp=NULL;
  6. fp=fopen("file.c","w+");
  7. if(NULL==fp)
  8. {
  9. return -1;
  10. }
  11. char buf[] = "abcdefghijklmnopqrstuvwxyz";
  12. fwrite(buf, sizeof(char), 26, fp);
  13. fseek(fp, 0, SEEK_SET);
  14. memset(buf, 0, 26);
  15. fread(buf, sizeof(char), 10, fp);
  16. printf("%s\n", buf);
  17. fseek(fp, 5, SEEK_CUR);
  18. memset(buf, 0, 26);
  19. fread(buf, sizeof(char), 10, fp);
  20. printf("%s\n", buf);
  21. fseek(fp, -10, SEEK_END);
  22. memset(buf, 0, 26);
  23. fread(buf, sizeof(char), 10, fp);
  24. printf("%s\n", buf);
  25. fclose(fp);
  26. fp=NULL;
  27. return 0;
  28. }

6 ftell()的使用

6.1 问题

使用ftell()获取文件的大小。

6.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:ftell()的使用

代码如下所示:

  1. #include <stdio.h>
  2. int main(void)
  3. {
  4. FILE*fp=NULL;
  5. fp=fopen("file.c","r");
  6. if(NULL==fp)
  7. {
  8. return -1;
  9. }
  10. fseek(fp, 0, SEEK_END);
  11. long len = ftell(fp);
  12. printf("文件长度为:%ld个字节\n", len);
  13. fclose(fp);
  14. fp=NULL;
  15. return 0;
  16. }

上述代码中,以下代码:

  1. FILE*fp=NULL;

定义一个FILE类型的指针fp。

上述代码中,以下代码:

  1. fp=fopen("file.c","r");
  2. if(NULL==fp)
  3. {
  4. return -1;
  5. }

使用函数fopen用r的方式打开一个文件file.c。

上述代码中,以下代码:

  1. fseek(fp, 0, SEEK_END);

使用函数fseek设置文件指针fp的位置为文件尾开始的第一个字节。

上述代码中,以下代码:

  1. long len = ftell(fp);

使用函数ftell获得指定文件的文件指针当前位置距离文件头的第一个字节的字节数。如果文件当前位置在文件尾开始的第一个字节,即文件最后一个字节的下一个位置,则将得到文件长度。

上述代码中,以下代码:

  1. printf("文件长度为:%ld个字节\n", len);

打印文件长度。

上述代码中,以下代码:

  1. fclose(fp);
  2. fp=NULL;

使用函数fclose关闭打开的文件。

6.3 完整代码

本案例的完整代码如下所示:

  1. #include <stdio.h>
  2. int main(void)
  3. {
  4. FILE*fp=NULL;
  5. fp=fopen("file.c","r");
  6. if(NULL==fp)
  7. {
  8. return -1;
  9. }
  10. fseek(fp, 0, SEEK_END);
  11. long len = ftell(fp);
  12. printf("文件长度为:%ld个字节\n", len);
  13. fclose(fp);
  14. fp=NULL;
  15. return 0;
  16. }

7 字符的输入输出

7.1 问题

使用字符的输入输出函数实现文件的复制。

7.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:字符的输入输出

代码如下所示:

  1. #include <stdio.h>
  2. int main(void)
  3. {
  4. FILE*fp = NULL;
  5. fp = fopen("file.c","r");
  6. if(NULL == fp)
  7. {
  8. return -1;
  9. }
  10. FILE*fp1 = NULL;
  11. fp1 = fopen("file副本.c","w");
  12. if(NULL == fp1)
  13. {
  14. return -1;
  15. }
  16. char ch;
  17. while ((ch = getc(fp)) != EOF)
  18. putc(ch, fp1);
  19. fclose(fp);
  20. fp=NULL;
  21. fclose(fp1);
  22. fp=NULL;
  23. return 0;
  24. }

上述代码中,以下代码:

  1. FILE*fp=NULL;

定义一个FILE类型的指针fp。

上述代码中,以下代码:

  1. fp=fopen("file.c","r");
  2. if(NULL==fp)
  3. {
  4. return -1;
  5. }

使用函数fopen用r的方式打开一个文件file.c。

上述代码中,以下代码:

  1. FILE*fp=NULL;

定义一个FILE类型的指针fp。

上述代码中,以下代码:

  1. fp=fopen("file.c","w");
  2. if(NULL==fp)
  3. {
  4. return -1;
  5. }

使用函数fopen用w的方式打开一个文件file.c。

上述代码中,以下代码:

  1. char ch;
  2. while ((ch = getc(fp)) != EOF)
  3. putc(ch, fp1);

首先,在循环的结束条件处,使用函数getc从文件fp中读入一个字符。

然后,在循环体内,将读入的字符写入到另一个文件fp1中。

最后,设置一个循环,逐个字节地读入文件fp的内容,再逐个字节的写入文件fp1,直到文件fp结束,即读入的字节是EOF。

上述代码中,以下代码:

  1. fclose(fp);
  2. fp=NULL;

使用函数fclose关闭打开的文件。

上述代码中,以下代码:

  1. fclose(fp1);
  2. fp=NULL;

使用函数fclose关闭打开的文件。

7.3 完整代码

本案例的完整代码如下所示:

  1. #include <stdio.h>
  2. int main(void)
  3. {
  4. FILE*fp = NULL;
  5. fp = fopen("file.c","r");
  6. if(NULL == fp)
  7. {
  8. return -1;
  9. }
  10. FILE*fp1 = NULL;
  11. fp1 = fopen("file副本.c","w");
  12. if(NULL == fp1)
  13. {
  14. return -1;
  15. }
  16. char ch;
  17. while ((ch = getc(fp)) != EOF)
  18. putc(ch, fp1);
  19. fclose(fp);
  20. fp=NULL;
  21. fclose(fp1);
  22. fp=NULL;
  23. return 0;
  24. }

8 字符串函数的使用

8.1 问题

使用sscanf()和sprintf()处理字符串。

8.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:字符串函数的使用

代码如下所示:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. int main(void)
  5. {
  6. FILE*fp=NULL;
  7. fp=fopen("file.c","w");
  8. if(NULL==fp)
  9. {
  10. return -1;
  11. }
  12. char buf[] = "abcdefghijklmnopqrstuvwxyz";
  13. fprintf(fp, "%lu%s", strlen(buf), buf);
  14. fclose(fp);
  15. fp=NULL;
  16. fp=fopen("file.c","r");
  17. if(NULL==fp)
  18. {
  19. return -1;
  20. }
  21. char *buf1;
  22. int len;
  23. fscanf(fp, "%d", &len);
  24. buf1 = malloc(len) + 1;
  25. fscanf(fp, "%s", buf1);
  26. buf1[len] = 0;
  27. printf("%s\n", buf1);
  28. fclose(fp);
  29. fp=NULL;
  30. return 0;
  31. }

上述代码中,以下代码:

  1. FILE*fp=NULL;

定义一个FILE类型的指针fp。

上述代码中,以下代码:

  1. fp=fopen("file.c","w");
  2. if(NULL==fp)
  3. {
  4. return -1;
  5. }

使用函数fopen用r的方式打开一个文件file.c。

上述代码中,以下代码:

  1. char buf[] = "abcdefghijklmnopqrstuvwxyz";

定义一个字符数组buf,并对其进行初始化。

上述代码中,以下代码:

  1. fprintf(fp, "%lu%s", strlen(buf), buf);

使用函数fprintf将字符数组buf保存到文件中。

注意:在保存之前应先保存字符数组buf中的字符串长度。

上述代码中,以下代码:

  1. fclose(fp);
  2. fp=NULL;

使用函数fclose关闭打开的文件。

上述代码中,以下代码:

  1. fp=fopen("file.c","r");
  2. if(NULL==fp)
  3. {
  4. return -1;
  5. }

使用函数fopen用r的方式重新打开文件file.c。

上述代码中,以下代码:

  1. char *buf1;
  2. int len;

首先,定义一个字符指针buf1。

然后,定义一个整型变量len。

上述代码中,以下代码:

  1. fscanf(fp, "%d", &len);
  2. buf1 = malloc(len) + 1;

首先,使用fscanf函数从文件中读入字符串的长度到变量len中。

然后,根据len中的值使用malloc函数为字符指针buf1申请存储空间。加1是为了给字符串结束符\0留出位置。

上述代码中,以下代码:

  1. fscanf(fp, "%s", buf1);
  2. buf1[len] = 0;
  3. printf("%s\n", buf1);

首先,使用fscanf函数从文件中从文件中读入字符串。

然后,将字符数组buf1中的最后一个字节置为\0。

最后,使用printf函数验证读入的内容。

上述代码中,以下代码:

  1. fclose(fp);
  2. fp=NULL;

使用函数fclose关闭打开的文件。

8.3 完整代码

本案例的完整代码如下所示:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. int main(void)
  5. {
  6. FILE*fp=NULL;
  7. fp=fopen("file.c","w");
  8. if(NULL==fp)
  9. {
  10. return -1;
  11. }
  12. char buf[] = "abcdefghijklmnopqrstuvwxyz";
  13. fprintf(fp, "%lu%s", strlen(buf), buf);
  14. fclose(fp);
  15. fp=NULL;
  16. fp=fopen("file.c","r");
  17. if(NULL==fp)
  18. {
  19. return -1;
  20. }
  21. char *buf1;
  22. int len;
  23. fscanf(fp, "%d", &len);
  24. buf1 = malloc(len) + 1;
  25. fscanf(fp, "%s", buf1);
  26. buf1[len] = 0;
  27. printf("%s\n", buf1);
  28. fclose(fp);
  29. fp=NULL;
  30. return 0;
  31. }

9 可变长参数的使用

9.1 问题

可变长函数参数是指定义一个函数,该函数的参数个数为不确定的值,如printf函数。

9.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:可变长参数的使用

代码如下所示:

  1. #include <stdio.h>
  2. #include <stdarg.h>
  3. int max(int cnt, ...)
  4. {
  5. va_list v;
  6. va_start(v, cnt);
  7. int maxvalue = va_arg(v, int);
  8. for(int i = 1; i < cnt; i++)
  9. {
  10. int data = va_arg(v, int);
  11. if(data > maxvalue)
  12. maxvalue = data;
  13. }
  14. va_end(v);
  15. return maxvalue;
  16. }
  17. int main(void)
  18. {
  19. int maxNum = max(10, 55, 34, 28, 16, 47, 62, 77, 86, 91, 9);
  20. printf("最大数为:%d\n", maxNum);
  21. return 0;
  22. }

上述代码中,以下代码:

  1. int max(int cnt, ...)
  2. {
  3. va_list v;
  4. va_start(v, cnt);
  5. int maxvalue = va_arg(v, int);
  6. for(int i = 1; i < cnt; i++)
  7. {
  8. int data = va_arg(v, int);
  9. if(data > maxvalue)
  10. maxvalue = data;
  11. }
  12. va_end(v);
  13. return maxvalue;
  14. }

定义了一个函数max。用于求参数中的最大值。在该函数中,以下语句:

  1. va_list v;

定义可变长参数表变量v。在该函数中,以下语句:

  1. va_start(v, cnt);

使用函数va_start将参数cnt之后的那些参数保存到v中。在该函数中,以下语句:

  1. int maxvalue = va_arg(v, int);

使用函数va_arg从参数表中取一个int类型参数放入变量maxvalue中,并假设maxvalue保存的是所有参数中的最大值。在该函数中,以下语句:

  1. int data = va_arg(v, int);
  2. if(data > maxvalue)
  3. maxvalue = data;

首先,使用函数va_arg从参数表中取一个int类型参数放入变量data中。

然后,将变量data与变量maxvalue对比,如果data大于maxvalue,则将data赋值给maxvalue,以保证maxvalue中保存的永远是最大值。在该函数中,以下语句:

  1. for(int i = 1; i < cnt; i++)
  2. {
  3. int data = va_arg(v, int);
  4. if(data > maxvalue)
  5. maxvalue = data;
  6. }

设置循环,将cnt后的参数,逐个遍历,找出最大值。在该函数中,以下语句:

  1. va_end(v);

使用函数va_end释放可变长参数表v。

上述代码中,以下代码:

  1. int main(void)
  2. {
  3. int maxNum = max(10, 55, 34, 28, 16, 47, 62, 77, 86, 91, 9);
  4. printf("最大数为:%d\n", maxNum);

在主函数中,使用函数max,找出参数中的最大值,并输出。

9.3 完整代码

本案例的完整代码如下所示:

  1. #include <stdio.h>
  2. #include <stdarg.h>
  3. int max(int cnt, ...)
  4. {
  5. va_list v;
  6. va_start(v, cnt);
  7. int maxvalue = va_arg(v, int);
  8. for(int i = 1; i < cnt; i++)
  9. {
  10. int data = va_arg(v, int);
  11. if(data > maxvalue)
  12. maxvalue = data;
  13. }
  14. va_end(v);
  15. return maxvalue;
  16. }
  17. int main(void)
  18. {
  19. int maxNum = max(10, 55, 34, 28, 16, 47, 62, 77, 86, 91, 9);
  20. printf("最大数为:%d\n", maxNum);
  21. return 0;
  22. }
时间: 2024-11-10 12:45:05

C语言04函数与递归的相关文章

【学习ios之路:C语言】函数及递归的简单应用

函数定义: 返回值类型 函数名(形参列表){函数体(函数的实现内容)}; 函数定义的四种形式: //函数定义第一种形式: 无参数, 无返回值 void byMilk() { //如果没有参数,小括号必不可少. printf("没钱\n"); } //函数名的命名规范:由多个英文单词组成,除了第一个单词的首字母小写,其余单词首字母大写. //函数定义第二种形式,有返回值,无参数 float salary() { printf("同志们辛苦了\n"); return 0

c语言中函数的递归

题目:用递归法把一个整数转换成字符串输出. 比较下面两种方法的不同: putchar(n%10+'0')的位置不同,造成输出结果的不同. 方法一: 1 #include <stdio.h> 2 void convert(int n) 3 { 4 int i; 5 if((i=n/10)!=0) 6 convert(i); 7 putchar(n%10+'0'); 8 9 } 10 main() 11 { 12 int n; 13 printf("请输入一个整数n:\n");

(C语言)函数的递归

问题描述: 编写递归函数,函数应该和下面的函数原型匹配: int hermite(int n,int x) Hermitee Polynomials(厄密多项式)是这样定义的: n <= 0; 1: Hn(x) = n = 1; 2x; n >= 2; 2xHn-1(x)-2(n-1)Hn-2(x); \ 代码如下: /*编写递归函数,函数应该和下面的函数原型匹配: int hermite(int n,int x) Hermitee Polynomials(厄密多项式)是这样定义的: n &l

C语言学习-函数和递归函数

C源程序是由函数组成的,有且只有一个主函数(main()函数). 一.函数 1.自定义函数的书写格式: 返回值类型 函数名(参数类型 形式参数1,参数类型 形式参数2,…) { 函数体 }例如: 1 include <stdio.h> 2 void test(); 3 4 int main() { 5 test(); 6 return 0; 7 } 8 9 void test() { 10 11 printf("hello world!"); 12 13 } 2.定义函数的

c语言--函数与递归

1.函数又叫方法,是指实现某项功能或完成某项任务的代码块 //函数的主体从大括号开始,从大括号结束 //函数组成 //main函数,是给系统调用的函数 //函数组成: 返回值, 函数名, 传入参数 //如: 实现两个整数相加,返回它们的和 void show(void) { printf("hello world!\n"); } int add(int x, int y) { return x+y; } int main(int argc, const char * argv[]) {

C语言之函数调用11—递归法求Hermite函数

/*递归法! ========================================== 题目: Hermite 函数:输入n.x,求Hn(x)? H0(x)=1; H1(x)=2*x; Hn(x)=2*x*Hn-1(x)-2*(n-1)Hn-2(x); ========================================== */ #include<stdio.h> float H(int n,int x) { if(n==0) return 1; if(n==1) r

黑 马 程 序 员_视频学习总结&lt;C语言&gt;----04 预处理指令

---------------------- ASP.Net+Unity开发..Net培训.期待与您交流! ---------------------- 一.预处理指令简介 1.C语言在对源程序进行编译之前,会先对一些特殊的预处理指令作解释(比如之前使用的#include文件包含指令),产生一个新的源程序(这个过程称为编译预处理),之后再进行通常的编译 2.为了区分预处理指令和一般的C语句,所有预处理指令都以符号"#"开头,并且结尾不用分号 3.预处理指令可以出现在程序的任何位置,它的

紫书第4章 函数和递归

1  序 系统的整理下第四章的学习笔记.同上次一样,尽量在不依赖书本的情况下自己先把例题做出来.这次有许多道题代码量都比较大,在例题中我都用纯C语言编写,但由于习题的挑战性和复杂度,我最终还是决定在第五章开始前,就用C++来完成习题.不过所有的代码都是能在C++提交下AC的. 在习题中,我都习惯性的构造一个类来求解问题,从我个人角度讲,这会让我的思路清晰不少,希望自己的一些代码风格不会影响读者对解题思路的理解. 其实在第四章前,我就顾虑着是不是真的打算把题目全做了,这些题目代码量这么大,要耗费很

Python基础之内置函数和递归

本文和大家分享的主要是python中内置函数和递归相关内容,一起来看看吧,希望对大家学习python有所帮助. 一.内置函数 下面简单介绍几个: 1.abs() 求绝对值 2.all() 如果 iterable 的所有元素都为真(或者如果可迭代为空),则返回  True 3.any() 如果 iterable 的任何元素为真,则返回  True .如果iterable为空,则返回  False 4.callable() 如果  object 参数出现可调,则返回  True ,否则返回  Fal