c笔记

 

第一章       概述

 

设计特性

 

1)       强大的控制结构。

 

2)       高效性

 

3)       可移植性(除特定的访问硬件部分)

 

4)       功能强大unix操作系统的大部分便是C编写的。

 

5)       面向编程人员,可以操纵内存中的特定位。

 

6)       优点和缺点,优点即是缺点,给予编程人员更多的自由,同时也会产生很多不容易发现的错误。

 

发展方向

 

使用步骤

 

1)       定义程序目标

 

2)       设计程序

 

3)       编写代码

 

4)       编译

 

5)       运行程序

 

6)       测试和调试程序

 

7)       维护和修改程序

 

编程机制

 

分两步:编译和连接。

 

分为源文件------>目标文件------>可执行文件

 

 

可执行文件比目标代码多了启动代码和库代码。

 

语言标准

 

C89/c90/ANSI C 、新标准为 C99

 

 

 

 

........

.........

.........

.........

.........

 

 

 

数组和指针

 

Int powers[8] = {1,2,4,6,8,16,32,64};初始化仅asic C

 

常量数组:const int days[months]={31,28,31,30,31,30,31,31,30,31,30,31};

 

在函数的内部声明,并且没有使用关键字static,不同的存储类具有不同的属性,因此不能把本章的只是推广到其它的存储类。例如:没有进行初始化,一些存储类的变量和数组会把它们的存储单元设置为0;数组则直接读取上面的内容。

 

如果不初始化数组,数组元素和未初始化的普通变量一样,其中存储的是无用的数值;但是如果部分初始化数组,未初始化的元素则被设置为0

 

如果初始化列表中的项目的个数大于数组大小,编译器会毫不留情地认为这是一个错误。但是用另外一种形式可以避免受到编译器的此类奚落:您可以省略括号中的数字,从而让编译器自动匹配数组的大小,和初始化列表中的项目数目。

 

Sizeof days / sizeof days[0];

 

C99可以对单个数组元素赋值,

 

Int arr[6] = {[5] = 212};其它的都为0

 

又如:

 

Int days[MONTHS] = {31,28,[4] = 31,30,31,[1] = 29};

 

结果为:31,29,0,0,31,30,31,0,0,0,0,0

 

 

声明数组时在方括号内只能使用整数常量表达式,整数常量表达式是由整数常量组成的表达式,sizeof表达式被认为是一个整数常量。而和c++不一样,一个const值却不是整数常量。并且该表达式的值必须大于0

 

 

变长数组 VLA

 

2维数组的初始化:

 

 

一维数组时一行,2维是一个面,3维是一个立方体。

 

指针和数组

 

对指针+1的结果就是对该指针增加一个尺存储单元,对于数组而言,地址会增加到下一个元素的地址。而不是下一个字节。

 

1.       指针的数值就是它所指向的对象的地址,指向float的指针,地址的内部表示方式是由硬件来决定的,很多计算机包含多个字节的数据类型,比如double类型的变量,对象的地址通常指的是其首字节的地址。

 

2.       指针前运用运算符* 就可以得到该指针所指向的对象的数值。

 

3.       对指针加1,等价于对指针的值加上它所指向的对象的字节大小。

 

在函数原型或函数定义头的场合中,可以用int * ar代替 int ar[],无论在任何情况下,形式int * ar都表示ar是指向int的指针。形式int ar[]也可以表示ar是指向int的指针,但只是在声明形式参量时才可以这样使用,使用第二中形式可以提醒读者ar不仅指向一个Int数值,而且它指向的这个int是一个数组中的元素。

 

由于原型允许省略名称因此下面的声明是等价的:

 

Int sum (int *ar,int n);

 

Int sum (int *,int);

 

Int sum (in tar[],int n);

 

Int sum (int [], int);

 

定义函数时,名称是不可以省略的,因此,在定义时下面两种形式是等价的:

 

Int sum(int *ar,int n)

 

{

 

}

 

Int sum (in tar[],int n)

 

{

 

}

 

 

 

Int marbles[size];

 

 

 

Sizeof marbles 是整个数组的大小,

 

Sizeof ar或者sizeof tar 就是单个数组元素的大小。

 

 

 

也可以传递首指针和尾指针

 

Int sump(int * start,int * end)

 

{

 

 Int total = 0;

 

While(start < end )

 

{

 

  Total += *start;

 

Start++;

 

}

 

}

 

 

 

 

 

 

 

c中,两个表达式 ar[i] *(ar+i) 的意义是等价的,而且不管ar是一个数组名还是一个指针变量,这两个表达式都可以工作,然而只有当ar是一个指针变量时,才可以使用ar++这样的表达式。

 

指针操作

 

指针之间的减法结果等于相对于他们的类型的值,比如

 

Pi+3 –pi=3,这个3相对于他们的类型int而言就是34字节的地址长度。

 

指针可以直接赋值给以个指针。

 

计算机并不检查指针是否依然指向某个数组元素,C保证指向数组的指针和指向数组后的第一个地址的指针都是有效的,但是如果指针在进行了增量或减量运算后超出了这个范围,后果将是未知的,另外,可以对指向数组元素的指针进行取值运算,但不能对指向数组后的第一个地址的指针进行取值运算,尽管这个指针式合法的。

 

Int *pt;

 

*pt = 5;

 

这是不可行的,因为pt的值是随机的,所以随机地址赋值为5,可能是重要的位置。

 

由于参数传递数组的时候是传递地址的,所以可以改变原数组的值,但是如果不想改变要保护原数组的话,可以在函数原型和定义的形式参量声明中使用关键字const;

 

使用const来创建符号常量(const double PI = 3.14159),数组常量(const mars [3] ={1,2,3}),指针常量 int * const p=&a;,以及指向常量的指针 const int * p=&a;(const int a=3;)

 

1)       指针变量 int * p = &a;

 

2)       指针常量 int * const a = &b; 这里的a 是个指针常量它指向变量b的地址,不能再修改它的值,a = &c;是错误的。

 

3)       指向常量的指针它是变量指向的是一个常量

 

它是一个变量,但它指向的内容是常量。

 

Const int b = 1,c = 2;

 

Const int * a;

 

  A = &b;a = &c,由于它本身是变量,所以可以改变它的值,再用它指向常量c.

 

但是它指向的内存是常量,是不能被修改的。如: *a = 20;是错误的。

 

还有另外一种写法 int const * a;const的位置,还是在*前面;

 

4)       指向常量的指针常量它是常量,但是它指向的内容是常量

 

Cons int b = 1, c = 2;

 

Int const * const a = &b;

 

   看关键字constconst后面的不可修改。

 

   Int * const a =&b;//a不能被修改。

 

   Int const * a=&b; //const后面是*a,则说明*a不能被修改。

 

把常量或非常量数据的地址赋给指向常量的指针式合法的。

 

 

然而只有非常量的数据才可以赋给普通的指针:

 

 

所以要分三个点来看指向的是常量还是非常量,还有就是常量指针还是指针常量。

 

多维数组与指针

 

 

Int zippo[4][2]:

 

数组名zippo同事也是数组首元素的地址,本例中,zippo的首元素本省又是包含两个int的数组,因此zippo也是包含两个int数组的地址,

 

1)  Zippo是数组首元素的地址,所以zippo的值和&zippo[0]相同,另一方面,zippo[0]本身是包含两个整数的数组,因此zippo[0]的值同其首元素(一个整数)的地址&zippo[0][0]相同。简单的说zippo[0]是一个整数大小对象的地址,zippo是两个整数大小对象的地址,因为整数和两个整数组成的数组开始同一个地址,因此zippozipp[0]具有相同的数值。

 

2)  对一个指针加1,会对原来的数值加上一个对应类型大小的数值。在这方面,zippozippo[0]是不一样的,zippo所指向的对象的大小事两个int,而zippo0】所指向的大小事一个int,因此zippo+1zippo[0]+1的结果不同。

 

3)  对一个指针取值(使用运算符*或者带有索引的[]运算符)得到的是该指针所指向对象的数值,因为zipp[0]是其首元素zippo[0][0]的地址,所以 *(zippo[0])代表存储在zippo[0][0]中的数值,即是一个int数值,同样zippo代表其首元素的地址,但是zippo[0]本身就是int数的地址,&zippo[0][0],因此*zippo&zippo[0][0]。对这两个表达式同时应用取值运算符将得到 **zippo等价于*&zippo[0][0],后者简化为一个int zippo[0][0].简而言之,zippo是地址的地址,需要两次取值才可以得到通常的数值。地址的地址或指针的指针式双重间接地典型例子。

 

总结:数组名是它本身元素的首地址,所以一维数组中的数组名就是数组单个元素的第一个元素的首地址,而二维数组就是一维数组的数组,所以它的名称就是一维数组的第一组数组的地址,所以他们相加结果是不一样的。相加就相当于他们元素加1,一维数组的元素是一个元素,而二维数组加1就相当于一维数组的一组数组。三维一样是二维数组的数组。它加1相当于加一个二维数组的量。对于取值来说二维是一维的地址,所以要经过两次取值才能取到数。

 

 

Int * pz[2] //pz指向一个包含2int值得数组。加()是因为[]优先级高于*

 

              Int说明数组和指针都int型的。

 

Int * pz[]     //是指2个指向int值的指针构成的数组。

 

 

 

 

 

最后一行说明指针的指针不能赋给2维数组名。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值