C和指针 第一章至第三章 笔记

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012654756/article/details/88829664

学习语言的基础不如编写程序有趣,但不知道语言的基础会使你在编写程序时缺少乐趣

第一章 快速上手

删除C代码更好的方法:

#if 0

statements

#endif

stdio.h使我们可以访问标准IO库strandard I/O library

#define MAX_COLS 20,这是字面值常量

数组参数是传引用reference,是传址调用。标量和常量按值传递

软件开下最大处不在编写,而是维护

过时的注释不如没有

NUL是ASCII字符集中'\0'字符的名字,字节模式为全0。NULL指一个值为0的指针,这样表示可以告诉阅读的人这个值的目的。NULL定义在stdio.h

char input[MAX_INPUT];gets(inpput);gets将STDIN的一行字符串(换行符结尾)丢弃换行符后填入数组,并在结尾填入‘\0’。

字符串:一串以NUL字节结尾的字符,NUL不是字符串的一部分。

字符串常量string literal:双引号括起来的一串字符。

“Hello”,内存占6字节:h e l l o NUL。字符串常量保存在字符数组中,所以c没有显示的字符串类型。字符串常量不可修改,想修改就保存在数组里。字符串常量不可以复制给一个字符数组,因为它不是字符本身,而是一个指向储存字符地址的指针。

long:%ld , float:%f , double:%lf , char:%c

(ch = getchar()) != EOF,getchar从STDIN读取一个字符并reutrn,没有字符时返回EOF,以提示文件结尾。

getchar从标准输入读取一个字符,若输入没字符,则返回EOF,在stdio.h定义

可读性有时比效率重要

rearragne(char const * input, ...)

形参可以接收数组,传给函数的实际是指向数组起始位置的指针,也就是数组在内存的地址。

const作用:告诉别人我的意图是不可以修改这个变量;让编译器验证 是否违背意图

gets函数会在输入特别长的行时溢出,fgets不会,15章讲

总结:

使用#include避免重复声明,放置函数原型。

检查保证数组不越界

第二章 基本概念

学习语言的基础不如编写程序有趣,但不知道语言的基础会使你在编写程序时缺少乐趣

翻译环境:源代码被转换为可执行的机器指令

执行环境:执行代码

两种环境不必在一个device上,如cross compiler在host,运行在device上。

2,1,1 翻译阶段:

多个源文件通过编译过程转换为目标代码 object code,目标文件由链接器 linker 链接在一起,形成可执行程序。

编译过程:

preprocessor预处理,在源代码执行文本操作,如用实际值代替#define,读入#include的内容

parse解析,这是产生多数错误和警告的地方,然后产生目标代码。目标代码是机器指令的初步形式。

optimizer优化器对目标代码进一步处理,提高效率。

后缀约定:

目标文件:unix是.o,dos是.obj

编译和连接:

cc -c xx.x,产生.o,以后再链接

cc -lname,链接器在name 函数库中查找。

执行:

程序载入内存,

宿主环境用一个启动程序与程序链接,调用main,执行代码。

程序使用运行时stack,存储函数局部变量和返回地址。

也使用static静态内存,里面的变量在程序整个执行过程都保留着值。

终止:main函数返回或者执行了exit,宿主环境的启动程序得到控制权,做回收操作等。

词法规则:

三字母词 trigrph

字符转义char escape

标识符:

不能以数字开头

第三章 数据

变量 3属性:作用域,链接属性,存储类型。

3属性决定了变量的可视性(何处可用)和生命周期(何时销毁)

3.1 基本数据类型

4个基本数据类型:整形,浮点型,指针,聚合类型(数组,结构体等)

int型分singed, unsigned,定义是这样的:long int至少和int一样长,int至少和short int一样长。

变量的最小范围:

char 0-127,()

singed char -127-127, x^8

unsinged char 0-255, 1111 1111 1111 1111对应256

unsigned int 0-65535 ,1111 1111 1111 1111 ,2^16是65535,0XFFFF

显示的声明为signed和unsigned可以提高可移植性。

一,整形字面值,

字面值是字面值常量的缩写,literal也译为常量。它不可以发生改变。

整形值有9种,写的是哪一个?

字面值后面添加字符L或者l,解释为long,

U或者u指定为unsigned,

ul就是unsigned long

宽字符常量 wide char literal:L'X'

0x是16进制,0是8进制。还有字符常量,用单引号围起来。

二,枚举类型

enumerated就是指它的值为符号常量而不是字面值的类型,

enum jar_type{ cpu, pint, quart}; //声明了类型jar_type,

enum Jar_Type mil_jug, gas_can; //声明了jar_type类型的变量

组合:

enum jar_type{cpu, pint}

milk_jug,gas_can;

这种类型的变量实际以整形存储,这些符号名的实际值都是整形值

3.1.2 浮点类型

浮点数字字面值总是写成十进制形式,后面跟L或l为long double类型,跟F,f表示float类型

3.1.3指针

一,指针常量 pointer constant

你可以通过操作符获得一个变量的地址而不是直接把它的地址写成字面值0常量的形式。

除了NULL 0,把指针常量表达为数值字面值几乎没用

二,字符串常量string literal

C语言没有字符串类型,但是有字符串常量,

字符串存储在字符数组中,这也是C没有显示的字符串类型的原因。

选择NUL作为字符串终止符是因为它不是一个可打印的字符。

K&R:具有相同的值的不同字符串常量在内存中是分开存储的。所以许多编译器允许程序修改字符串常量。

ANSI:对字符串常量修改是undefined,

如果要修改,请把字符串存储在数组里面

字符串常量会生成一个指向字符的常量指针。

当字符串常量出现在表达式,表达式使用的值是字符存储的地址,而不是字符本身,

所以不能把字符串常量复制给一个字符数组,因为字符串常量的直接值是一个指针,而不是字符本身。

3.2 基本声明

说明符 声明表达式列表

说明符specifier包含了一些关键字,描述被生命标识符的类型,也可以改变标识符的缺省存储类型和作用域。

signed关键字只用于char,其他整形默认就是有符号。

浮点型只能使用long double,

声明数组:

编译器不检查数组下标引用是否超过范围,需要程序检查。

技术上说,编译器可以做到,但是代价很大。

声明指针:

int *a; //*执行间接访问操作,indirection

char * msg = "Hello world"; //声明msg为指向字符的指针,用字符串常量的1st 字符的地址对该指针初始化。

看上去赋给*msg,实际是给msg:

char *msg;

msg = "hello";

3.3 typedef

为数据类型定义新名字,声明方式与普通的相同,只是把typedef 关键字写前面:

char *ptr_to_char ; //普通声明

typedef char *ptr_to_char ; //加typedef

prt_to_char a; //使用char *的新名字

它可以减少声明又臭又长的危险,

而且需要修改类型时,修改一处容易的多

3.4 常量

int const *pci; //指向的值是const

int * const pci; //指针本身是const

#define是另一种创建常量的方法:

创建名字常量:#define MAX 50 ; int const max=50 ;

前置更好,他可以用在使用字面值常量的地方比如声明数组的长度,而const变量只能用于使用变量的地方。

3.5 作用域

变量可以被访问的区域由标识符的作用域scope决定。

它决定了:作用域之外变量不可被访问;不同作用域的变量可以同名

编译器可确定4个类型的作用域:

文件作用域、函数作用域、代码块作用域、原型作用域

3.6 链接属性:

组成程序的源文件被编译后,目标文件和从函数库引用的函数链接在一起,形成可执行程序。

如果相同标识符出现在不同源文件,标识符的链接属性决定如何处理不用文件出现的标识符。

链接属性分为external,internal,none,

none:没链接属性的标识符总是当做单独的个体,该标识符的多个声明被当做独立的实体

internal:同一源文件里所有声明指同一实体,不同源文件的多个声明属于不同实体

external:声明多少次、位于几个源文件,都属于同一实体。

extern和static用于在声明中修改标识符的链接属性。

如果声明(函数或者变量的)默认有external链接属性,则static后变为internal。否则static代表静态变量。

3.7存储类型

变量的存储类型决定变量何时创建,销毁。

分别是:普通内存,运行时堆栈,硬件寄存器。

变量缺省存储类型取决于声明位置。

任何代码块之外声明的变量存储在静态内存,不在堆栈,称为静态static变量,他们无法指定其他存储类型,它们在程序运行之前创建,执行期间都存在。

代码块内部声明的变量的缺省存储类型是automatic,在堆栈中。执行到代码块时才会创建自动变量,每次执行都重新创建变量。

加static会将automatic变为static变量,但是这不会修改作用域。

函数形参不可以声明为静态,因为实参在堆栈中传递给函数,用于支持递归。

register用于自动变量的声明,提示存储在硬件寄存器而不是内存,成为寄存器变量。他们访问效率高,但编译器不一定理会。如寄存器变量过多,编译器会自动处理。指针声明为寄存器变量可以提高效率,特别是频繁执行间接访问的指针。也可以把函数形参声明为寄存器变量,编译器会把他们从堆栈复制到寄存器,但可能复制这些值的开销大于优化节省的时间空间。

寄存器变量的生命周期和自动变量相同,但是需要额外工作。使用寄存器变量的函数返回之前,这些寄存器先前储存的值必须恢复,来确保调用者的寄存器变量没有破坏,使用运行时堆栈完成这个任务,函数执行时,它把要使用的所有寄存器内容保存在堆栈中。函数返回时,这些值再复制回寄存器。

一般硬件实现中,不为寄存器指定地址。由于寄存器值的保存和恢复,某个特定寄存器在不同的时刻所保存的值不同,所以,一般不向你提供寄存器变量的地址。

初始化:

静态变量和自动变量的初始化有一个重要差别,静态变量初始化中,可以把可执行程序文件想要初始化的值放在程序执行时变量会使用的位置。当可执行文件载入内存,这个初始值会赋值给变量。

自动变量初始化需要更多开销,因为程序链接时还无法判断其存储位置。函数局部变量在函数的每次调用中位置都可能不同。所以,自动变量没有缺省初始值,除了const常量,自动变量声明时初始化相比其赋值语句,效率没有提高。自动变量每次都重新初始化,静态变量只在程序开始执行前初始化一次。

3.8 static关键字

不同的context,static具有不同的意思,

它用于函数定义时,或代码块外的变量声明时,用于修改标识符的链接属性,从external改为internal。

在代码块内部时,用于修改变量的存储类型。

还差2页的内容

猜你喜欢

转载自blog.csdn.net/u012654756/article/details/88829664
今日推荐