Standard C Episode 4

稍微简单的复杂数据类型:数组

   计算机程序处理的对象是数据信息(计算机中的信息包括数据信息和控制信息),计算机内存可以存储大量信息,姑且可以认为只有存储在内存中的数据信息才是可 以使用的。内存由操作系统管理,程序要使用内存存储空间需要向操作系统申请并被成功分配后才可以使用,C语言提供的变量声明(定义)语句可以实现向操作系 统申请存储空间。

   C语言提供的变量声明(定义)语句实现向操作系统申请存储区(存储空间),变量名有"两个代表",一是代表所申请到的存储区,一是代表存储区里面存放的数 据信息。数组声明(定义)语句可以实现一次性向操作系统申请成倍的存储空间,数组名有"两个代表",一是代表所申请到的(整个)存储区,二是代表着获得的 成倍存储空间的首存储单元首地址。要注意的是:数组名根本不能代表所申请的全部存储区里面存放的数据信息。数组的"数组名"和函数的"函数名"非常类似, 数组名代表数组首元素的首地址,函数名代表函数中首条代码的地址(我们知道,程序语句可以分组,顶级分组就是函数)。

附:
/*
 * 函数指针:指向函数的指针
 *
 * 函数名称代表函数本身整个存储区,函数名称还代表着函数中的第一条语句的地址。函数名取址是函数地址,是整个函数的地址。这和数组名称一样,数组名称代表数组本身的整个存储区,数组名称还代表数组第一个元素的地址。数组名取址是整个数组的地址。
 *
 * 函数地址。 从地址信息上看函数地址就是函数中第一条语句所在的地址。
 *
 * */

#include <stdio.h>

int main()
{
    int add(int , int);
    printf("add是%p\n", add);
    printf("&add是%p\n", &add);

    int (*p_f)(int, int);
    p_f = add;
    printf("p_f(1, 1)是%d\n", p_f(1, 1));

    return 0;
}

int add( int value, int value1)
{
    return value + value1;
}




关于数组的分析:
    int integer_arr[100];
            //当一次性成功申请了100倍的可以放整型数据的存储空间后,integer_arr一是代表所申请的整个存储区(看看 sizeof(integer_arr)就知道了),integer_arr再就是代表着获得的成倍存储空间的首存储单元的首地址(具体就 是&integer_arr[0])。
            //因为integer_arr代表着整个存储区,所以&integer_arr是整个数组的地址(可以想象这个地址值是和integer_arr一样的,值都是&integer_arr[0])

分析:
    integer_arr + 1和&integer_arr + 1的区别

函数
    程序语句可以分组,分组可以一层又一层的进行下去,顶级分组就是函数。函数实现了对程序语句的分组。不同的函数通过函数名区分,函数名有"两个代表",一是代表整个函数所在代码区,二是代表函数所在代码区里的首条语句首地址。
    函数分为函数头和函数体,函数头单独出现叫做函数声明。

注意:传统上C语言(C89)是不支持变长数组功能的,也就是说数组长度是在编译期间就确定下来的,不能在运行期改变。不过在C99标准中已经允许定义变长数组。然而,C99所允许的变长数组是使用是有限制的。
    由于变长数组的长度是在编译时无从得知的,因此变长数组的存储空间位于栈中。

 

 1 /*
 2  * 数组初始化练习
 3  * */
 4 
 5 #include <stdio.h>
 6 int main()
 7 {
 8     //int arr[3] = {1, 2, 3};
 9     //int arr[3] = {1, 2, 3, 4, 5};//这种情况下,编译器编译会给出警告,同时编译器丢掉多余元素
10     //int arr[] = {1, 2, 3, 4, 5};//这种情况下,编译器自动计算数组元素个数然后成倍申请内存空间,然后给出初始值。
11     int arr[3] = {1};//编译器在这种情况下,会自动将其他未指明初始值的元素初始化为零
12     int loop = 0;
13     for (loop = 0; loop < 3; loop++)
14         printf("%d\t", arr[loop]);
15     putchar('\n');
16 
17     return 0;
18 }

 

 

 1 /*
 2  * 二维数组练习
 3  *
 4  * 注意:多维数组从右到左依次是低维-高维
 5  * */
 6 
 7 #include <stdio.h>
 8 int main()
 9 {
10     //int arr[3][4] ={{11, 12, 13, 14}, {21, 22, 23, 24}, {31, 32, 33, 34}};
11     //int arr[3][4] ={{11, 12 }, {21, 22, 23, 24}, {31, 32, 33, 34}};
12     //int arr[3][4] ={{11, 12 }};//部分初始化,那么,没有被明确给出初始化值的,编译器用零来自动补全其他未初始化元素
13     //int arr[][4] ={{11, 12 }, {21, 22, 23, 24}, {31, 32, 33, 34}};//不一定非要指明最高维度的数组长度,编译器可以根据初始化表来算出
14     int arr[3][4] ={11, 12, 31, 32, 33, 34};//这种情况的初始化表并没有指明某一维度数组初始化哪个数值,所以编译器读取初始化表,然后逐一赋值给arr[0][0],arr[0][1], arr[0][2],...,arr[1][0], arr[1][1],...
15     //int arr[3, 4]//错误,gcc编译器报错
16     //int arr[12/4][4]//正确,[]中可以出现表达式
17     int row = 0, col = 0;
18 
19     for (row = 0; row < 3; row++) {
20         for (col = 0;col < 4; col++)
21             printf("%d ", arr[row][col]);
22         putchar('\n');
23     }
24     putchar('\n');
25 
26 }

 

 

 1 /*
 2  * 变长数组
 3  * 注意:传统上C语言(C89)是不支持变长数组功能的,也就是说数组长度是在编译期间就确定下来的,不能在运行期改变。变长数组的长度是在编译时无从得知的。
 4  * */
 5 
 6 #include <stdio.h>
 7 
 8 int main()
 9 {
10     int students;
11     unsigned i = 0;
12     printf("请输入学生人数:");
13     scanf("%d", &students);
14     float scores[students];
15     printf("students是%d\nsizeof(scores)是%d\n", students, sizeof(scores));
16 
17     printf("请输入学生人数:");
18     scanf("%d", &students);
19     printf("students是%d\nsizeof(scores)是%d\n", students, sizeof(scores));
20     
21 
22     for (i = 0;i < students;i++)
23         scanf("%f", &scores[i]);
24     for (i = 0; i < students; i++)
25         printf("%f\t", scores[i]);
26     printf("students是%d\nsizeof(scores)是%d\n", students, sizeof(scores));
27     putchar('\n');
28     return 0;
29 
30 }

 

 

 

 

函数
    程序语句可以分组,分组可以一层又一层的进行下去,顶级分组就是函数。函数实现了对程序语句的分组。不同的函数通过函数名区分,函数名有"两个代表",一是代表整个函数所在代码区,二是代表函数所在代码区里的首条语句首地址。

    函数分为函数头和函数体,函数头单独出现叫做函数声明。

    函数中的return;语句主要功能在于立即结束函数的执行,她的附带作用是想主调函数传送一个返回值。也就是说,函数在执行过程中将会在遇到 return语句或者遇到函数右大括号时候立即结束函数执行。需要注意的是,当由return语句传送一个返回值时候必须在函数头中指明返回值类型。

注意:    return;//立即停止执行当前函数执行,返回主调函数。
        exit(0);//功能执行比return更强硬,exit();语句立即终止程序执行,将参数返回给操作系统,相当于位于main函数的return语句。exit()函数在头文件stdllib.h里面。

    主调函数的函数调用语句的函数参数称为"实际参数",简称"实参";被调函数函数定义时定义的参数变量称为"形式参数",简称"形参"。C语言实参向形参只进行"值传递"。

    C语言源程序中函数的声明应避免依赖编译器的隐式声明。我们应该在源程序的开头把文件中所有函数的声明都列出来。否则有可能在编译时候导致编译器进行隐式声明,这种声明方式可能引起问题,我们应该在源程序中避免编译器的隐式声明。

 1 /*
 2  * 函数练习 - 隐式函数声明
 3  *
 4  * 以下源程序是可以编译通过的,因为gcc聪明了,当她编译到语句value = add(2, 3)时,自行假定了add函数声明是int add();这叫做"隐式声明"。
 5  *
 6  * 正因存在隐式声明int add();所以编译就通过了。但是,若实际的add函数是void add();那么gcc的假定就是错误的,所以编译会报错
 7 
 8      C语言源程序中函数的声明应避免依赖编译器的隐式声明。我们应该在源程序的开头把文件中所有函数的声明都列出来。否则有可能在编译时候导致编译器进行隐式声明,这种声明方式可能引起问题,我们应该在源程序中避免编译器的隐式声明。
 9  * */
10 
11 #include <stdio.h>
12 
13 
14 void show(int value)
15 {//output
16     printf("计算结果是");
17     printf("%d\n", value);
18 
19     return ;
20 }
21 
22 int main()
23 {
24     int value = 0;
25     value = add(2, 3);
26     show(value);
27 
28     return 0;
29 }
30 
31 
32 int add(int value1, int value2)
33 {//add
34     return value1 + value2;
35 }

 

 1 /*
 2  * 函数练习
 3  * 编辑read函数和show函数,show从键盘读入一个整数,由show函数输出
 4  * */
 5 
 6 #include <stdio.h>
 7 
 8 int read();
 9 void show(int);//该语句书写为void show();编译也可以通过,函数声明语句可以供编译器编译本源程序时候使用
10 
11 int main()
12 {
13     int value = 0;
14     value = read();
15     show(value);
16 
17     return 0;
18 }
19 
20 int read()
21 {
22     int value;
23     printf("请输入一个整数:");
24     while (!scanf("%d", &value)){
25         scanf("%*[^\n]");
26         scanf("%*c");
27         printf("程序未能从输入流中提取到整数,请再次输入一个整数:");
28     }
29     scanf("%*[^\n]");
30     scanf("%*c");
31     return value;
32 }
33 
34 void show(int value)
35 {
36 
37     //fflush(stdout)可以把输出缓冲区中的所有内容立刻显示在屏幕上
38     printf("%d\n", value);
39 
40     return ;
41 }

 

 

 1 /*
 2  * 汉诺塔问题
 3  * */
 4 
 5 #include <stdio.h>
 6 
 7 unsigned han_nuo_ta(int value, char a, char b, char c);
 8 main()
 9 {
10     int value = 0;
11     char a = 'A', b = 'B', c = 'C';
12     scanf("%d", &value);
13     han_nuo_ta(value, a, b, c);
14 }
15 
16 unsigned han_nuo_ta(int value, char a, char b, char c)
17 {
18     static unsigned counter = 0;
19     if (value != 1) {
20         han_nuo_ta(value - 1, a, c, b);
21         printf("第%d步:%d盘子%c -> %c\n", ++counter, value, a, c);
22         han_nuo_ta(value - 1, b, a, c);
23         return counter;
24     }
25     else 
26     {
27         printf("第%d步:%d盘子%c -> %c\n", ++counter, value, a, c);
28         return counter;
29     }
30 }

 

 

 1 /*
 2  * 函数练习
 3  * */
 4 
 5 #include <stdio.h>
 6 
 7 void func()
 8 {
 9     printf("abc\n");
10     //return;//立即停止执行当前函数执行,返回主调函数。
11     //exit(0);//功能执行比return更强硬,exit();语句立即终止程序执行,将参数返回给操作系统,相当于位于main函数的return语句。exit()函数在头文件stdllib.h里面。
12     printf("def\n");
13 
14     return ;
15 }
16 
17 int main()
18 {
19     func();
20     printf("xyz\n");
21 
22     return 0;
23 }

 

 

 

 

 1 /*
 2    变长参数表函数的定义和使用
 3 */
 4 #include <stdio.h>
 5 #include <stdarg.h>
 6 int max(int cnt, ...) {
 7     int ret = 0, loop = 0;
 8     va_list v;
 9     va_start(v, cnt);
10     for (loop = 0; loop < cnt; loop++) {
11         int value = va_arg(v, int);
12         if (value > ret) {
13             ret = value;
14         }
15     }
16     va_end(v);
17     return ret;
18 }
19 int main() {
20     printf("max(2, 9, 6)是%d\n", max(2, 9, 6));
21     printf("max(3, 19, 25, 2)是%d\n", max(3, 19, 25, 2));
22     return 0;
23 }

 

转载于:https://www.cnblogs.com/libig/p/4738222.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值