您的位置:首页 > 编程语言 > C语言/C++

黑马训练营--IOS基础学习总结--C语言总结5

2014-10-27 17:51 337 查看
C语言复习总结:
这个文件是在学习完C语言的基本用法后,回顾C语言的一些语法和易错,不易理解的一下内容,可能会存在内容不连续的情况.

本文内容,有参考自M了个J的博客根据自身的学习进行了部分的摘抄和扩写
原文请参考:http://www.cnblogs.com/mjios/tag/objective-c/default.html?page=1

图片 没 传成功 我稍后再试试

预处理指令:

一、宏定义:

1、不带参数的宏定义

#define宏名字符串

#define ABC 10

作用:在编译预处理时,将源程序中所有"宏名"替换成右边的"字符串",常用来定义常量。

使用习惯与注意

1宏名一般用大写字母,以便与变量名区别开来,但用小写也没有语法错误

2对程序中用双引号扩起来的字符串内的字符(字符串),不进行宏的替换操作。

3定义一个宏时可以引用已经定义的宏名

4宏名的有效范围是从定义位置到文件结束。如果需要终止宏定义的作用域,可以用#undef命令

5在编译预处理用字符串替换宏名时,不作语法检查,只是简单的字符串替换。只有在编译的时候才对已经展开宏名的源程序进行语法检查

2、带参数的宏定义

#define 宏名(参数列表)字符串

#define average(a, b) (a+b)/2

将源程序中所有宏名替换成字符串,并且将字符串中的参数用宏名右边参数列表中的参数替换

使用注意

宏名和参数列表之间不能有空格,否则空格后面的所有字符串都作为替换的字符串

#define average (a, b) (a+b)/2

2

3int main ()

4 {

5 int a = average(10,4);//
int a = (a, b) (a+b)/2(10,4);

6 return0;

7 }

2> 带参数的宏在展开时,只作简单的字符和参数的替换,不进行任何计算操作。所以在定义宏时,一般用一个小括号括住字符串的参数。

下面定义一个宏D(a),作用是返回a的2倍数值:

如果定义宏的时候不用小括号括住参数

1 #include <stdio.h>

2

3#defineD(a)
2*a

4

5int main ()

6 {

7 int b =D(3+4);

8

9 printf("%d", b);

10 return0;

11 }

第7行将被替换成int
b = 2*3+4;,输出结果:

如果定义宏的时候用小括号括住参数,把上面的第3行改成:

#defineD(a) 2*(a)

注意右边的a是有括号的,第7行将被替换成int
b = 2*(3+4);,输出结果:

3> 计算结果最好也用括号括起来

下面定义一个宏P(a),作用是返回a的平方:

如果不用小括号括住计算结果

1 #include <stdio.h>

2

3#definePow(a)
(a) * (a)

4

5int main(int
argc,constchar * argv[]) {

6 int b =Pow(10)
/Pow(2);

7

8 printf("%d", b);

9 return0;

10 }

注意第3行,没有用小括号扩住计算结果,只是括住了参数而已。第6行代码被替换为:

int b = (10) * (10)
/ (2) * (2);

简化之后:int b = 10 * (10 / 2) * 2;,最后变量b为:

如果用小括号括住计算结果

将上面的第3行代码改为:

#definePow(a) ( (a) * (a) )

那么第6行被替换为:

int b = ( (10) * (10)
) / ( (2) * (2) );

简化之后:int b = (10 * 10) / (2 * 2);,最后输出结果:。这个才是我们想要的结果。

也就意味着前面的#define average(a, b) (a+b)/2应该写成#define
average(a, b) (((a)+(b))/2)

二、条件编译

基本用法

1#if条件1

2 ...code1...

3#elif条件2

4 ...code2...

5#else

6 ...code3...

7#endif

1> 如果条件1成立,那么编译器就会把#if与#elif之间的code1代码编译进去(注意:是编译进去,不是执行,很平时用的if-else是不一样的)

2>如果条件1不成立、条件2成立,那么编译器就会把#elif与
#else之间的code2代码编译进去

3> 如果条件1、2都不成立,那么编译器就会把#else与
#endif之间的code3编译进去

4> 注意,条件编译结束后,要在最后面加一个#endif,不然后果很严重(自己思考一下后果)

5> #if 和 #elif后面的条件一般是判断宏定义而不是判断变量,因为条件编译是在编译之前做的判断,宏定义也是编译之前定义的,而变量是在运行时才产生的、才有使用的意义

其他用法

1.#if defined()#if!defined()的用法

#if和 #elif后面的条件不仅仅可以用来判断宏的值,还可以判断是否定义过某个宏。比如:

1#ifdefined(MAX)

2 ...code...

3#endif

如果前面已经定义过MAX这个宏,就将code编译进去。它不会管MAX的值是多少,只要定义过MAX,条件就成立。

条件也可以取反:

1#if !defined(MAX)

2 ...code...

3#endif

如果前面没有定义过MAX这个宏,就将code编译进去。

2.#ifdef#ifndef的使用

* #ifdef的使用和#ifdefined()的用法基本一致

1#ifdefMAX

2 ...code...

3#endif

如果前面已经定义过MAX这个宏,就将code编译进去。

* #ifndef又和#if
!defined()的用法基本一致

1#ifndefMAX

2 ...code...

3#endif

如果前面没有定义过MAX这个宏,就将code编译进去。

上面的#ifdef#ifndef可以很好地解决
重复声明头文件的现象


三、文件包含

.1种形式#include <文件名>

直接到C语言库函数头文件所在的目录中寻找文件

2种形式
#include
 "文件名"

系统会先在源程序当前目录下寻找,若找不到,再到操作系统的path路径中查找,最后才到C语言库函数头文件所在目录中查找

使用注意:

1.#include指令允许嵌套包含,比如a.h包含b.h,b.h包含c.h,但是不允许递归包含,比如
a.h 包含 b.h,b.h包含
a.h

2、使用#include指令可能导致多次包含同一个头文件,降低编译效率

解决方法,使用条件编译,判断是否已经定义了某个某文件,如果是不在进行重复定义,否则,在进行定义

变量的存储类型:

1.自动变量

1>定义:自动变量是存储在堆栈中的。

2>哪些是自动变量:所有的局部变量在默认情况下都是自动变量。

3> 生命周期:在程序执行到声明自动变量的代码块(函数)时,自动变量才被创建;当自动变量所在的代码块(函数)执行完毕后,这些自动变量就会自行销毁。如果一个函数被重复调用,这些自动变量每次都会重新创建。

2.静态变量

1> 定义:静态变量是存储在静态内存中的,也就是不属于堆栈。

2> 哪些是静态变量:

所有的全局变量都是静态变量

被关键字static修饰的局部变量也是静态变量

3> 生命周期:静态变量在程序运行之前创建,在程序的整个运行期间始终存在,直到程序结束。

1 #include <stdio.h>

2

3int
a;//全局变量为静态变量只会执行一次

4

5void test() {

6 staticint
b =0; //全局变量为静态变量只会执行一次

7 b++;

8

9 int c =0;

10 c++;

11

12 printf("b=%d, c=%d \n", b, c);

13 }

14

15int main() {

16 int i;

17 //
连续调用3次test函数

18 for (i =0;
i<3; i++) {

19 test();

20 }

21

22 return0;

23 }

* 第3行的变量a、第6行的变量b都是静态变量,第9行的变量c、第16行的变量i是自动变量。

* 因为第6行的变量b是静态变量,所以它只会被创建一次,而且生命周期会延续到程序结束。因为它只会创建一次,所以第6行代码只会执行一次,下次再调用test函数时,变量b的值不会被重新初始化为0。

* 注意:虽然第6行的变量b是静态变量,但是只改变了它的存储类型(即生命周期),并没有改变它的作用域,变量b还是只能在test函数内部使用。

* 我们在main函数中重复调用test函数3次,输出结果为:

staticextern与函数

1.static

* 在定义函数时,在函数的最左边加上static可以把该函数声明为内部函数(又叫静态函数),这样该函数就只能在其定义所在的文件中使用。如果在不同的文件中有同名的内部函数,则互不干扰。

* static也可以用来声明一个内部函数

2.extern

* 在定义函数时,如果在函数的最左边加上关键字extern,则表示此函数是外部函数,可供其他文件调用。C语言规定,如果在定义函数时省略extern,则隐含为外部函数。

* 在一个文件中要调用其他文件中的外部函数,则需要在当前文件中用extern声明该外部函数,然后就可以使用,这里的extern也可以省略。
直接在前面声明 void test();j即可

staticextern的总结

1.extern可以用来声明一个全局变量,但是不能用来定义变量

2.默认情况下,一个全局变量是可以供多个源文件共享的,也就说,多个源文件中同名的全局变量都代表着同一个变量

3.如果在定义全局变量的时候加上static关键字,此时static的作用在于限制该全局变量的作用域,只能在定义该全局变量的文件中才能使用,跟其他源文件中的同名变量互不干扰

结构体:

结构体定义的集中方式:

1.先定义结构体类型,再定义变量

1struct Student {

2 char *name;

3 int age;

4 };

5

6struct Student stu;

2.定义结构体类型的同时定义变量

struct Student {

char *name;

int age;

} stu;

3.直接定义结构体类型变量,省略类型名

struct {

char *name;

int age;

} stu;

结构体的注意点:

1、不允许对结构体本身递归定义

结构体中不能定义自身类型的变量

2、结构体内可以包含别的结构体

3.定义结构体类型,只是说明了该类型的组成情况,并没有给它分配存储空间,就像系统不为int类型本身分配空间一样。只有当定义属于结构体类型的变量时,系统才会分配存储空间给该变量

4.结构体变量占用的内存空间是其成员所占内存之和,而且各成员在内存中按定义的顺序依次排列

结构体初始化:

将各成员的初值,按顺序地放在一对大括号{}中,并用逗号分隔,一一对应赋值

struct Student {

2 char *name;

3 int age;

4 };

5

6struct Student stu = {"MJ",27};

结构体的使用

1.一般对结构体变量的操作是以成员为单位进行的,引用的一般形式为:结构体变量名.成员名

stu.age = 27;

2.如果某个成员也是结构体变量,可以连续使用成员运算符"."访问最低一级成员

stu.age = 27;

3.相同类型的结构体变量之间可以进行整体赋值

struct Student stu2 = stu1;

结构体数组:

1、定义方法:

struct Student {

char *name;

int age;

};

struct Student stu[5];//定义1

struct Student {

char *name;

int age;

} stu[5];//定义2

struct {

char *name;

int age;

} stu[5];//定义3

2.初始化

struct {

char *name;

int age;

} stu[2] = { {"MJ",27},
{"JJ",30} };

结构体作为函数参数

将结构体变量作为函数参数进行传递时,其实传递的是全部成员的值,也就是将实参中成员的值一一赋值给对应的形参成员。因此,形参的改变不会影响到实参

1 #include <stdio.h>

2

3//
定义一个结构体

4struct Student {

5 int age;

6 };

7

8void test(struct
Student stu) {

9 printf("修改前的形参:%d
\n", stu.age);

10 //
修改实参中的age

11 stu.age =10;

12

13 printf("修改后的形参:%d
\n", stu.age);

14 }

15

16int main(int
argc,constchar * argv[]) {

17

18 struct Student stu = {30};

19 printf("修改前的实参:%d
\n", stu.age);

20

21 //
调用test函数

22 test(stu);

23

24

25 printf("修改后的实参:%d
\n", stu.age);

26 return0;

27 }

输出结果为:,形参是改变了,但是实参一直没有变过

指向结构体的指针

结构体指针变量的定义形式:struct结构体名称
*
指针变量名

有了指向结构体的指针,那么就有3种访问结构体成员的方式

结构体变量名.成员名

(*指针变量名).成员名

指针变量名->成员名

1 #include <stdio.h>

2

3int main(int
argc,constchar * argv[]) {

4 //
定义一个结构体类型

5 struct Student {

6 char *name;

7 int age;

8 };

9

10 //
定义一个结构体变量

11 struct Student stu = {"MJ",27};

12

13 //
定义一个指向结构体的指针变量

14 struct Student *p;

15

16 //
指向结构体变量stu

17 p = &stu;

18

19 /*

20 这时候可以用3种方式访问结构体的成员

21 */

22 //
方式1:结构体变量名.成员名

23 printf("name=%s, age = %d \n", stu.name, stu.age);

24

25 //
方式2:(*指针变量名).成员名

26 printf("name=%s, age = %d \n", (*p).name, (*p).age);

27

28 //
方式3:指针变量名->成员名

29 printf("name=%s, age = %d \n", p->name, p->age);

30

31 return0;

32 }

输出结果:

typedef的用法:

起别名:

1、给基本书籍类型起别名

typedefint Integer;

Integer i = -10;

2、给指针起别名

typedefchar *String;

String str ="This is a string!";

3、给结构体起别名

// 定义一个结构体

2struct MyPoint
{

3 float x;

4 float y;

5 };

// 起别名

8typedefstruct
MyPointPoint;

12Point p;

同时结构体起别名的方式还有:

/ 定义一个结构体,顺便起别名

typedefstruct MyPoint
{

float x;

float y;

} Point;

甚至可以省略结构体名称:

typedefstruct {

float x;

float y;

} Point;

4、给指向结构体的指针起别名

// 定义一个结构体并起别名

4typedefstruct
{

5 float x;

6 float y;

7 }Point;

//起别名

10typedefPoint
*PP;

13 //
定义结构体变量

14 Point point = {10,20};

15

16 //
定义指针变量

17 PP p = &point;

18

5、指向枚举类型的指针

1//
定义枚举类型

2enum Season {spring, summer, autumn, winter};

3//
给枚举类型起别名

4typedefenum
SeasonSeason;

5

6int main(int
argc,constchar * argv[]) {

7 //
定义枚举变量

8 Season s = spring;

9

10 return0;

11 }

其他方法定义:

// 定义枚举类型,并且起别名

typedefenum Season {spring, summer, autumn, winter}Season

甚至可以省略枚举名称,简化为:

typedefenum {spring, summer, autumn, winter}Season;

6、指向函数的指针

1 #include <stdio.h>

2

3//
定义一个sum函数,计算a跟b的和

4int sum(int
a,int b) {

5 int c = a + b;

6 printf("%d + %d = %d", a, b, c);

7 return c;

8 }

9

10typedefint
(*MySum)(int,int);

11

12int main(int
argc,constchar * argv[]) {

13 //
定义一个指向sum函数的指针变量p

14 MySum p = sum;

15

16 //
利用指针变量p调用sum函数

17 (*p)(4,5);

18

19 return0;

20 }

typedef#define的区别

1typedefchar
*String1;

2

3#defineString2char
*

4

5int main(int
argc,constchar * argv[]) {

6 String1 str1, str2;

7

8 String2 str3, str4;

9 return0;

10 }

第1行给char *起了个别名String1,第2行定义了宏String2。然后在第6、第8行定义了4个变量。

重点来了,注意:在这种情况下,只有str1、str2、str3才是指向char类型的指针变量,str4只是个char类型的变量。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: