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 }
时间: 2024-12-08 02:56:21

Standard C Episode 4的相关文章

Standard C episode 1

计算机内存可以记录大量的信息,只有记录在内存中的信息才是可以使用的.计算机的内存管理者是操作系统.程序可以根据需要向操作系统申请存储区,所有存储区必须先申请并经过操作系统分配后才能由程序使用.我们知道计算机里的信息可以简单划分为: /指令       /控制信息 信息 -            \控制字       \数据信息                     |              /              \      数值信息     非数值信息       /    \ 

Standard C Episode 3

程序语言中的控制流语句用于控制各计算操作执行的次序.控制流结构有:(1)顺序结构(2)分支结构(3)循环结构 if...else语句是经典的分支结构控制语句,同样"switch (表达式)...case 常量表达式" 语句也可以实现分支处理."表达式"可以是任何表达式,"常量表达式"也可以是任何常量表达式.case分支一般包含多条语句时也不必用大括号括起来,因 为每一个case分支只会给出switch分支结构中语句执行的开始位置,而不确定终止位置

Standard C Episode 5

理解变量标识符的作用域和可见性,以及变量生存期. (1)标识符的作用域和可见性     作用域:作用域是一个标识符在源程序中有效的区域.     可见性:程序运行到某一点,能够引用到的标识符,就是该处可见的标识符. (2)变量生存期:     变量的生存期就是指变量从创建到销毁的时间范围.变量按照生存期分“静态生存期”和“动态生存期”.静态生存期:如果变量的生存期与程序的运行期相同,则称该变量具有“静态生存期”; 动态生存期:变量生存期始于创建声明点,结束于作用域结束处. 注意:源程序声明(定义

Standard C Episode 2

源程序中,但凡可以出现某种类型的数据的地方都可以用同类型的表达式替换.一个表达式的类型,取决于多个方面. 操作符有单目操作符和双目操作符, 还有三目操作符(? : 是C语言唯一的一个三目操作符)."目"指的是操作数的个数! C语言没有指定同一操作符的多个操作数的计算顺序(除了&& || ? : 和,).所以语句x = f() + g();的计算结果依赖不同的编译器. 1 /* 2 * 文件名: 3mu.c 3 * 描述:(1)一个表达式的类型取决于多个方面(表达式的操作

Standard C Episode 6

字符串.字符串是以'\0'结尾的字符序列.C语言字符串在内存中的存储规则:按照串中字符出现的顺序在内存中连续存储,末尾是字符串结束符'\0'. 注:'\0'(查ASCII码表可知'\0'就是0)是表示字符串的字符,它的位置决定了一个字符串中有效字符的个数. 字符串常量.字符串常量在源程序词法记号中属于"文字",它和其他文字"数字.布尔文字.以及字符"一样.但区别是“字符串常量文字代表的是首字符地址”. 注:编译器编译时候会把源程序中重复出现的相同文字只存储一回.多个

Standard C Episode 8

C语言函数和程序结构 通过函数可以把大的计算任务分解成若干个较小任务,从而使得思路更加清晰,同时函数也大大提高了代码的复用率,提高了工作效率.要注意的是多函数之间应该尽可能地高聚合低耦合.另一方面,一个程序可以保存在一个或者多个源文件中.各个文件可以单独编译. 注意:一般地,头文件中不会放那些在程序运行时发生具体效应的语句.例如声明(定义)一个变量的语句是不会放在头文件中的.再例如结构体声明(定义)语句就可以放头文件里,但结构体变量声明(定义)语句是不会放在头文件中的. make工具可以用来进行

Standard C Episode 9

typedef关键字可以给数据类型起别名. 结构体.结构体可以如下定义一个结构体变量 1 /* 2 * 结构体 3 * */ 4 #include <stdio.h> 5 /*struct { 6 int age; 7 char gender; 8 float height; 9 } student;//声明(定义)无名结构体的同时定义了结构体变量student 10 */ 11 /*struct student { 12 int age; 13 char gender; 14 float h

Standard C Episode 10

标准库函数malloc/calloc/realloc以及free的堆内存分配与回收 1 /* 2 * malloc练习 3 * 4 * */ 5 6 #include <stdlib.h> 7 #include <stdio.h> 8 9 int main() 10 { 11 int *p_value = NULL; 12 13 p_value = (int *) malloc (1 * sizeof(int)); 14 if (p_value) { 15 printf("

Standard C Episode 7

编译预处理 #define可以定义宏.宏可以带参数,叫做带参数的宏,其参数叫做宏的参数. #undef 可以解除宏的定义. 1 /* 2 宏练习 3 */ 4 5 #include <stdio.h> 6 #define NEG( r) r = 0 - r 7 8 main() 9 { 10 int value = 4; 11 NEG(value); 12 printf("value是%d\n", value); 13 } 1 /* 2 宏练习 3 */ 4 #includ