C语言进阶学习日志

【C语言进阶学习日志】
***Week01***
10/06~寻找资源,搞定装备
1、需要什么工具学习C?哪个适合自己用?适合初学者用?适合进阶学习者用?
2、有哪些视频可以一同参考学习?

10/08~
1、代码风格:函数名用大小写字母,一般变量用小写字母,寄存器变量用大写字母;下划线什么时候用?
2、数组和指针的联系
3、c语言中字符串连续输出,中间不能为空。如字符串“12 00AD”,打印输出为“12”。从而也无法通过一帧连续的报文将“12 00AD”输出,
可以通过转换为十六进制的方式输出;或者加入空字符(如何实现?)


***Week02***
10/31
1、计算机本质:程序的机器。
2、机器语言(电信号)、汇编语言(符号)面向机器、高级语言;前两种语言依赖于机器特性,在不同机器上不兼容。
3、高级语言。通过编译程序软件,将高级语言编写的程序(称为:源程序)转换为机器指令的程序(称为:目标程序)。
4、面向过程(程序面对的是过程中的细节)的语言:C语言;面向对象(程序面对的是一个个对象,对象是由数据及对数据进行的操作组成的)的语言:
C++、C#、Visual Basic、Java
5、C语言:语法限制不大严格,程序设计自由度大。不要过分依赖C语言编译程序差错。“限制”和“灵活”是一对矛盾。
6、C语言用途:专门为编写系统软件而设计(可以执行好,硬件控制能力高)。主要用途之一:嵌入式系统程序
7、stdio.h:标准输入输出函数头文件(standard input&output)。在程序中要用到“标准函数库”中的输入输出函数,则需在相应文件模块的开头写上:
#include <stdio.h>
8、C程序中的注释:程序进行预编译处理时,会将每个注释替换为一个“空格”,因此,编译时注释部分不产生目标代码,注释对运行不起作用。

11/01
1、声明:包括变量、函数。一个函数中,对使用的变量和调用的函数,需要对其做“声明”。作用在于:函数由上至下执行,需要知道该东西是什么,包含哪些信息
2、C语言程序的结构:程序-->源程序-->函数,三者依次往下包含。源程序包括:预处理指令、全局声明、函数定义。
3、程序的编译过程:一个源程序进来-->编译系统的“预处理器”对预处理指令进行预处理-->将预处理的结果与程序其他部分放在一起,
组成一个可编译的源程序-->编译程序对该源程序进行编译,得到目标程序
4、工程(多个程序模块)的编译过程:各源程序编译得到各对应的目标程序-->所有目标程序连接成为一个统一的二进制的可执行程序
5、全局变量 vs 局部变量:前者在整个源程序内有效,后者只在函数范围内有效。
6、函数定义:该函数实现了什么功能。
7、C语言程序的特点:(1)函数是C程序的基本单位;(2)main函数本身是一个函数,程序执行由此进入,并由此退出.不论main函数在程序中处于哪个位置;
(3)C程序由一个或多个函数组成,但main函数只有一个;(4)程序中对计算机的操作由函数中的C语句完成。
8、C程序的运行:用C语言写好源程序-->编译程序(即:编译器)把C源程序编译成目标程序(二进制文件)-->将该目标程序与系统的库函数及其他目标程序连接,
形成可执行的目标程序。

11/07
1、程序设计:任务需求-->任务解决-->写出文档
2、程序的调试(debug)和测试(test):debug——通过上机发现程序中的故障;test——设计多组测试数据,发现程序中存在的漏洞。
3、软件:计算机程序+程序文档的总称。

11/08
1、调试时,用scanf函数输入变量的值时,需要用“,”隔开 。如:1,2,3

11/09
1、每个变量和函数都具有两个属性:数据类型、数据存储类别。
2、数据存储类别:数据在内存中存储的方式。C的存储类别一共有4种:自动的(auto)、静态的(static)、寄存器的(register)、外部的(extern)
3、数据存储类别作用:决定变量的“作用域”、“生存期”。
4、C程序中默认数据存储类别为:auto。
5、自动局部变量:如果没有赋初值的话,每次调用该函数时,该变量的值都不确定(每次函数调用结束后,存储单元释放,下次调用时重新分配存储单元)
6、静态局部变量:如果没有赋初值的话,编译时自动赋初值0(对数值型变量)或空字符'\0'(对字符变量)。

11/10
1、scanf函数的正确形式:scanf("%d%d%d",&a,&b,&c);  //输入a, b, c时,用空格隔开、enter输入隔开都可以
2、用到scanf函数时,为了方便他人知道要输入的内容,在scanf函数前加上一条printf函数语句(注:是printf语句)。如:printf("Please enter three integer number:");
3、关键字extern的定义:对变量用extern作“外部变量声明”,表示把该外部变量的作用域扩展到此位置。实质为扩展变量的作用域。
其内含前提:该变量是一个全局变量
4、extern的由来:一个全局变量A的作用域:从定义处到文件结束,在A定义之前的函数不能引用A这个外部变量。
而且,一个程序中的多个源程序文件中都定义了外部变量A,则在进行程序的连接时会报错:重复定义。
这时,需要用到extern将变量的作用域扩展到需要引用A的函数中。
5、extern的使用:分两种情况:1)在一个源程序文件中扩展外部全局变量A。提倡用以下方式避免在该种情况下使用extern:在源程序文件的开头或者引用A的所有函数之前定义A;;
2)在其他源程序文件中扩展A。
6、extern使用技巧:函数调用中形参可不用。定义形参变量为全局变量,然后在调用函数中用extern声明该变量,将形参变量的作用域扩展到调用函数中。
7、extern语法:例如int A为需声明的外部变量。声明时,写成: extern A; 或者 extern int A。变量的类型名可省略,因为extern不是要定义变量,而只是声明。

11/14
1、函数内调用函数时,把函数当成变量,需要重新定义数据类型。
举例1:假如定义了函数:int define(void),那么在main()中调用该函数的语法为:
    int define(); int a = define();            //正确
    define();                                  //错误
    int a; a = define();                       //错误。没有给出define()的数据类型定义
    int define(); printf("a = %d", define());  //正确
举例2:定义了函数:void define(),则main()中调用该函数的语法为:
    void define();    define();                //正确
    void define();                             //错误。没有书写define()函数进行调用。
2、C-Free不支持主函数为空函数的写法:void main(){}; 编译不过去
3、static可以对全局变量进行声明,语法为:static A。作用是:限定A在“本文件”中,防止其他文件误用
4、概念明晰:全局变量、局部变量、动态存储、静态存储
全局变量与局部变量,定义的是变量的作用域;
而动态存储和静态存储定义的是变量的存储方式。
注:全局变量默认为静态存储方式,如果不赋值,则初值为0;局部变量默认为动态存储方式,如果不赋值,则初值随机。
1)用static声明全局变量:使该变量的作用域限定在本文件中;
2)用static声明局部变量:使该变量存储在静态存储区,程序执行过程中不会释放所分配的空间。
5、static的使用:用auto, register, static声明变量时,需跟变量定义一起用,而不能单独使用。
int a;  static a;                         //错误。编译时会被认为重新定义
static int a;                             //正确。

11/16
1、指针即为一个变量的地址。存储地址的变量称为“指针变量”。
2、弄懂指针,首先要明确变量的存储和读取。如果程序中定义了变量A,则编译时,会对A分配内存单元(即一定长度的空间,长度根据编译系统及变量数据类型定),
也即:程序经过编译后,变量名A转换为了A的地址,对A的存取都是通过该地址进行的。
3、指针的由来:一般的变量(例如 i=3)为直接访问变量的值,而指针可以通过间接方式(变量的地址)访问变量的值。

11/18
1、函数中有全局变量,是否意味着该函数有返回值?如果是,则int insulation_const(void)正确,而void insulation(void)则错误
A:真实原因是,没有进行函数声明。
2、函数的类型定义根据?

11/19
1、在VC++ 6.0中,函数内的变量及被调用函数的定义,必须放在函数首部(即所有命令语句前);而C-Free则自由,可放在函数中部。
2、指针变量的定义:类型名 *指针变量名。如:int *p;
注:“类型名”用来指定该变量可以指向的变量类型。如“int *p"说明p只能指向int型变量,而不能指向float等类型变量
3、指针变量中只能存放地址(指针),定义指针变量时,不要将一个常数赋给一个指针变量。如:int *p = 100; 为非法语句。
而如果指针变量定义了,*p = 100;为合法语句。举例:
int *p = &a;
*p = 100;         //表示将整数100赋值给a,相当于:a = 100

11/22
1、Q:得到函数返回值的方式:函数传参、定义全局变量。两种方式的优缺点?

11/23
1、变量给指针赋值的方式:
a)变量名:p = &a;(正确) 而 *p = a;(错误)。定义指针变量,同时对其进行初始化:int *p = &a;(正确)
b)常数:前提是指针p已经定义,且已赋值。int *p; p = &a; *p = 100;(正确)而int *p; *p = 100;(错误)
2、用指针的方式从大到小排序a,b,c,不会改变a,b,c原来的值:

11/27
1、指针的传参方式。指针类型函数参数的传递,传的是“地址”。即
int *p; deliver(p);(正确)   而deliver(*p);则错误。其中deliver是一个函数。
2、C语言的函数调用,实参变量与形参变量之间的传递:①方向:“单向的”,即实参变量-->形参变量,反之则不行。②传递的东西:值。③函数的返回值数量:有且只有一个。
可以用数组的方式实现多个返回值
3、在被调函数中改变实参指针所指向变量的值,可以改变主调函数中变量的值。
举例:《C程序设计(第4版)》中P226例8.3和P228例8.4

11/29
1、C语言中,“数组名”即表示该数组“首元素的地址”。
延伸1:对于数组a,有:(a + 1)指向的是数组a的第2个元素a[1]。*(a + 1)表示指向a[1]
延伸2:定义指针int *P; 和数组int a[5]; 且*p = a; 则有:*(a + i) 和*(p + i)等同,都是指向a[i]
2、指针数组定义同时附初值。int a[5] = {1, 2, 3, 4, 5}; int *p = a; 或者 int *p = &a[0];
3、如果指针变量*p指向数组a[10],则p也可以带“下标”,即p[i]语法正确,其相当于*(p+i)。缘由:下标[]在程序进行编译时,处理方法是转换为地址,即
p[i]被处理成*(p+i)。但需要注意p的当前指向位置。

12/22-->参考文档《高质量C++/C编程指南》
1、对头文件使用ifndef/define/endif结构,可以防止头文件被重复引用
举例:头文件graphics.h
#ifndef GRAPHICS_H
#define GRAPHICS_H
#endif
2、BOOL布尔变量与零值比较:不可将BOOL变量与TRUE、FALSE、0、1比较。如需比较,正确方式为:BOOL flag; if(flag)(表示flag为真);if(!flag)(表示flag为假)
3、整形变量与零值比较:采用==、!=直接与0比较。例:int i; if(i!=0)
4、浮点变量与零值比较:不可将浮点变量与诸如0.0、0.1、0.200之类的数用==、!=比较。因为float和double都有精度限值。正确方式为:
float i; if((i>=expension) && (i<=expension))
5、指针变量与零值比较:应当用==、!=与NULL进行比较。因为指针的零值是”空“(NULL)

1/21-->数组与指针作为函数形参可互用的本质
1、C编译器在对数组进行编译时,处理方法是转换为地址。-->对形参“数组名”进行编译时,处理方法是作为指针变量,也即传递的是地址。
2、数组与指针的共同之处在于:数组用的“下标法”指向数据,指针用的“地址”指向数据,两者在进行编译时,是等价的。即*(arr+i)与arr[i]无条件等价,无论
arr的定义是“int *arr;”,还是“int arr[];”。
3、数组名即为数组的首元素地址。
4、数组名或者指针作为形参,函数传递的是地址,形参值的改变会使实参值同步改变。
5、注:形参“数组名”按“指针变量”处理,也即可以对形参数组名(也即首元素地址)进行赋值;而实参数组名是不可以进行赋值的。
这是因为:实参数组名代表一个固定的地址(也即数组首元素的地址),固定的地址非变量;而形参数组名作为指针变量,指针变量是可以对地址进行赋值的。见如下:
int arr[5];
arr = arr + 3;        //compile failed、compilation errors、compilation fails
*arr = *(arr + 3);    //compile succeed、compile successfully、compilation succeeds
而void fun(arr[])
{
    arr = arr + 3;    //compile succeed
}

形参数组名是数组的首元素地址,那么如果定义数组int arr[5] = {1, 3, 4, 5, 6};那么*arr表示的数组首元素的值,即*arr = 1;

1/22-->sizeof VS strlen,指针
1、sizeof是一个关键字,非函数。不需要用头文件;而strlen是一个库函数,需要用头文件<string.h>
2、指针类型的赋值必须指向某个变量,而不能是常量。如:
int *p = 0;            //wrong.
int a;    int *p = a;    //wrong.
int a;    int *p = &a;    //correct.
int a;    int *p;    p = &a;    //correct.
3、对数组应用sizeof,可以得到整个数组分配的字节数(存储全部数据占用的内存字节数)。不同的C编译器,分配给char类型的空间长度都为1byte,而分配给short、int、
long、long long、float、double数据类型的长度则不尽相同,从而在计算除char类型以外的数据长度时,需要查看该编译器对数据类型的空间长度配置信息。
一般来讲,32位编译系统,对short、int分配2byte空间,对float、double、long、long long分配4byte长度。针对该32位编译系统,计算数组元素个数方式为:
char arr[] = {...};        int len = sizeof(arr);
short arr[]= {...};        int len = sizeof(arr) / 2;
int  arr[] = {...};        int len = sizeof(arr) / 2;
long arr[] = {...};        int len = sizeof(arr) / 4;
float arr[]= {...};        int len = sizeof(arr) / 4;
4、对指针应用sizeof,只是得到分配给用来存储一个地址值的指针所用的字节数,即4个字节。(无法通过指针计算所指向数组的长度,可以计算出数组的长度,然后
将该长度值作为形参传递)

猜你喜欢

转载自blog.csdn.net/Eigrl/article/details/81560045
今日推荐