原创 如何在面试C语言时立于不败之地

2009-9-28 21:08 3330 7 7 分类: 软件与OS

      下面是我最近看C语言的读书笔记,里面有很多以前弄不明白的知识点,现在终于豁然开朗啦,希望对大家有所帮助,其中有很多知识点是面试时经常问到而大家又常常答不上来的!


1C语言的基本数据类型


       C语言中,数据类型可分为基本数据类型、构造数据类型(包括数组、枚举、结构体和联合体)、指针类型、空类型四大类。C语言的基本数据类型包括整型、浮点型和字符型。


2、常用转义字符表




字符形式


含义


\n


换行,将当前位置移到下一行开头,相当于按Enter


\t


跳到下一个Tab位置,相当于按Tab


\b


退格,将当前位置移到前一列,相当于按BackSpace


\\


反斜杠字符\


\’


单引号字符’


\”


双引号字符”


\0


空字符,常用于字符串中


\ddd


13位的八进制数所代表的字符


\xhh


12位十六进制数所代表的字符


3、字符常量是用单引号括起来的一个字符;字符串常量是由一对双引号括起来的字符序列。字符串常量在内存中存储时,每个字符占用一个字节的内存空间,系统自动在字符串尾部加上一个字符‘\<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />0,以标识这个字符串的结束。


4printf使用的格式字符如下:


(1) d:以十进制输出整型值;


(2) o:以八进制输出整型值;


(3) x:以十六进制输出整型值;


(4) u:以无符号形式输出整型值;


(5) c:输出一个字符;


(6) s:输出一个字符串;


(7) f:输出一个浮点数;


(8) e:以科学表示法输出浮点数;


(9) g:输出%f%e中占用位数较短的一个。


对于长整型,除了可以使用%d方式输出,还可以以%ld的形式输出。注意:单精度浮点型(float)和双精度浮点型(double)都以%f的格式输出。


%与格式字符之间还可以加上一些说明符以对输出格式做进一步的限定:


(1) -:输出时左对齐,默认是右对齐;


(2) dd:指定输出的参数所占的最小宽度,如果数据的长度小于最小宽度则以空格来填补,如果数据的长度大于等于最小宽度则以原样输出;


(3) dd.dd:用于输出浮点数时,前面的dd表示整个浮点数所占的宽度,后面的dd表示小数点后面将输出几位;输出字符串时,前面的dd表示整个字符串所占的宽度,后面的dd表示输出字符串的前dd个字符。


5scanf的格式字符如下:


(1) d:期待输入一个十进制整型;


(2) o:期待输入一个八进制整型;


(3) x:期待输入一个十六进制整型;


(4) u:期待输入一个无符号整型;


(5) c:期待输入一个字符;


(6) s:期待输入一个字符串;


(7) f:期待输入一个浮点数;


(8) e:期待输入一个以科学表示法的浮点数。


5、命名规范


       (1) 标识符:在程序设计中,变量名、函数名、数组名等统称为标识符。C语言规定,标识符只能由字母(a~zA~Z)、数字(0~9)、下划线(_)组成,并且标识符的第一个字符必须是字母或下划线,不能以数字开头。


注意:C语言是区分大小写的。


(2) 关键字:关键字是由C语言规定的具有特定意义的字符串,通常也称为保留字。用户定义的标识符不应与关键字相同。C语言的关键字分为以下几类:类型说明符、语句定义符和预处理命令字。类型说明符是指用于定义、说明变量、函数或其他数据结构的类型,如intdouble等;语句定义符用于表示一个语句的功能,如iffor等;预处理命令字用于表示一个预处理命令,如includedefine等。


(3) 命名规范:Linux下建议的命名规则如下:变量名必须有一定的意义,并且意义明确;不建议大小写混用;在失去意义的情况下,尽量使用较短的变量名;函数名应以动词开头;尽量避免使用全局变量。


6C程序语句概述


       C语言既有完成单一任务的简单语句,也有由多条语句构成完成某一功能的复合语句。C语言以分号作为一个语句的结束。C程序的语句必为以下5种语句之一:(1) 空语句:空语句只有一个分号,它什么也不做。(2) 表达式语句:一个表达式加上一个分号就构成了一个语句。(3) 复合语句:复合语句又称块,是用一对大括号括起来的语句集合。块同时也标识了一个域,在一个块中定义的变量只能在该块的内部使用。(4) 函数调用语句:一个函数调用和一个分号就构成了一个函数调用语句。(5) 控制语句:控制语句用于控制程序的流程,C程序中有9种控制语句,如下所示:


       ifelse…:条件语句


       switch:多分支选择语句;


       for():循环语句;


       while():循环语句;


       dowhile():循环语句;


       continue:结束本次循环语句;


       break:结束整个循环语句或结束switch语句;


       return:函数调用返回语句;


       goto:转向语句(一般不使用,只在特殊情况下使用)


7C程序的3种基本控制结构:顺序结构、选择结构(或分支结构)和循环结构。


8case后面有多条语句时,不用加大括号以构成一个语句块,系统自动把它们当做一个语句块来执行。这是一个非常特殊的情况。当然加上大括号也可以。


9break只能用在switch语句和3中循环语句中。


10C程序中包含头文件有两种方法:


       (1) #include<myinc.h>


(2) #include”myinc.h”


第一种使用尖括号(<>),第二种使用双括号(“”)。对于第一种,编译器gcc在系统预设包含文件目录(/usr/include)中查找相应的头文件myinc.h。对于第二种,编译器gcc首先在当前目录中查找头文件,如果当前目录没有找到需要的头文件,就到指定的dirname目录中去寻找。


对于系统提供的头文件,通常以第一种方式包含到源程序中;对于自己编写的头文件,通常放在与源程序相同的目录中,并以第二种方法包含该源文件。


11、如果在定义一个函数时,没有明确指明返回类型,Linux上最常用的编译器gcc默认返回类型为int


12、形参与实参的类型应该相同或者两者间可以互换。


13、函数通过return语句将一个值返回给调用它的函数。一个函数体内可以有多条return语句,当实际执行到第一条return语句时,函数就执行完毕。


14、如果函数的返回类型与return语句返回的值类型不同,以函数的返回类型为准。对于数值类型将自动进行类型转换。


15、如果调用的函数是用户自定义的函数,而且该函数与调用它的函数在同一个文件中。若调用语句在函数定义之前,则应该对函数先进行声明;若调用语句在函数定义之后,则不必对函数进行声明。


16、函数可以嵌套调用但不可以嵌套定义。


17、变量的访问控制:变量按其在程序中被访问范围可分为两类:局部变量和全局变量。局部变量是指在一个函数内部定义的变量。


18、变量的存储类别:变量根据存储类别可以分为静态存储变量和动态存储变量,简称为静态变量和动态变量。所谓静态变量是指在程序运行期间分配固定的存储空间的变量,所谓动态变量是指在程序运行过程中根据需要动态分配内存空间的变量。动态变量主要有:函数的形参、函数内定义的非static变量。静态变量有:函数内定义的static变量、全局变量。动态变量函数调用后会立即销毁,而静态变量在函数调用结束后不会销毁,只有当整个程序运行结束后才会被销毁。


19、在所有函数外定义的数组的所有元素将自动赋予初值0,在函数内部定义的数组,系统不会为其进行初始化,在使用数组元素前必须对元素进行初始化。


20、对于二维数组,如果对全部元素都赋初值,则定义数组时第一维的维数可以省略,但第二维的维数必须指定。


21C语言中的指针是指专门用来存放内存地址的变量。每个指针都有一个与之关联的数据类型,该类型决定了指针所指向的变量的数据类型。


22、避免使用未初始化的指针。在定义指针时最好将其初始化为NULL,即明确指示当前指针不指示任何变量。


23、对于指针,有两个与其相关的运算符如下:


&:取地址运算符;


*:取指针所指向的内存单元的值。


24、在指向数组某个元素的指针上加上或减去一个整型数值,就可以指向另一个数组元素,前提是没有超出数组的范围。


25、注意区别:


*p++:先取得当前p所指向的变量值再使p指向后一个变量;


*p--:先取得当前p所指向的变量再使p指向前一个变量;


*++p:先使p指向后一个变量再取得p所指向的变量的值;


*--p:先使p指向前一个变量再取得p所指向的值。


26、数组元素也可以是指针类型,这种数组称为指针数组,也就是说指针数组的每一个元素都是一个指针变量;数组指针是指数组名实际上就是指向数组第一个元素的指针。


27、指针数组定义的一般形式:


       类型名 *数组名[数组长度]


       例如:int *p[5]


       由于运算符*的优先级低于运算符[],因此p先与[]结合,形成p[5]的形式,它显然是一个数组。然后再与*结合,表示数组元素的类型为指针,每个数组元素都指向一个整型变量。这里p就是一个二级指针,它是指针的指针。


28、区别int (*p)[5]int *p[5]:前者是一个指针,它指向一个含有5个元素的指针。后者是一个数组,它的长度为5,数组中的每一个元素指向一个整型变量。


29、如果一个函数的参数中有指针,那么出于程序健壮性的考虑,在函数中必须检查参数是否为NULL


30、注意区别:


(*p)++:取得指针p所指向的变量并将其加1


*p++:先取得当前p所指向的变量值再使p指向后一个变量。


31、数组,如char a[20]a是指向数组第一个元素的指针,它的值不可以被改变,它在程序运行过程中始终指向数组的第一个元素。而在函数定义中,如void copy_string(char src[],char dst[])srcdst也是一个指针,但它们的值是可以改变的,也就是说,它们可以指向其他字符变量。


32、不能将一个字符串常量或字符数组直接赋给另一个字符数组。字符串的数组只能使用strcpystrncpy或其他类似功能的函数。strcpy是不安全的,存在安全漏洞,容易被黑客所利用,因此一般应该使用strncpy


33、静态变量分为两种:全局静态变量和局部静态变量。全局静态变量是在所有函数之外定义的静态变量,局部静态变量是在某个函数内定义的变量。静态变量存储在内存的静态存储区,静态存储区在程序的整个运行期间都存在。未经初始化的静态变量会被程序自动初始化为0。全局静态变量的作用域是从定义之处开始到文件结尾,局部静态变量只在定义它的函数内有效。静态变量的用途有:(1) 限制变量的作用域;(2) 设置变量的存储域。


34、局部变量会在其作用域内暂时屏蔽全局变量。如:


#include<stdio.h>


<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 


int a = 3;


 


void f()


{


       int a = 1,i;


       printf("%d\n",a);


       for(i=0;i<1;i++)


       {


              int a="2";


              printf("%d\n",a);


       }


}


 


void main()


{


       f();


       printf("%d\n",a);


}


程序输出是:


1


2


3


35static全局变量与普通的全局变量有什么区别?static局部变量和普通的局部变量有什么区别?static函数与普通函数有什么区别?


       在定义变量时,全局变量之前再冠以static就构成了静态的全局变量。全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。两者在存储方式上并无不同,其区别在于非静态存储变量的作用于是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一个源程序的其它源文件中不能再使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数使用,因此可以避免其它源文件使用该变量。把普通全局变量改变为静态全局变量是改变了它的作用域,限制了它的使用范围。


       普通局部变量所在的函数每次被调用都会被重新定义并分配存储空间,而静态局部变量不会,它的值始终保持着。静态局部变量只被初始化一次,下次使用时依旧是上一次的值。


static函数(即静态函数,在函数定义前加上了static关键字)与普通函数作用域不同,它仅存在于本文件中。只在当前源文件中使用的函数应该声明为内部函数(即加上static关键字)。内部函数应该在当前源文件中声明和定义。对于可在当前源文件外使用的函数,应该在一个头文件中说明,要使用这个函数的源文件就要包含这个头文件。


程序的普通局部变量存在于堆栈中,全局变量、staitic局部变量存在于静态存储区中。


36void *malloc(unsigned int size)函数的功能是在内存的动态存储区分配一个长度为size字节的连续空间。函数返回的是一个指向分配域起始地址的指针,这个指针的类型是void类型;void  free(*p)函数的功能是释放由p所指向的内存区,使这部分内存归还给系统。p是调用malloc函数的返回值。注意:在程序中,malloc函数与free函数是成对出现的。使用malloc分配一块内存,使用完毕后必须使用free函数将其释放。


37、数组对越界访问是不会检查的,检查的任务由程序员自己来完成。我们在编写程序时要注意不能对数组进行越界访问,否则会导致一些严重的错误。


38C语言预处理命令:预处理命令并不是C语言的一部分,因此每条编译预处理命令不需要以分号来结束。编译预处理命令包括宏定义、文件包含和条件编译三类。


       C语言标准允许在程序中用一个标识符来表示一个字符串,称为宏。标识符称为宏名。在编译预处理时,将程序中所有的宏名用相应的字符串来替换,这个过程称为宏替换。宏分为两种:无参数宏和有参数宏。宏的作用范围是从宏定义开始到本源程序文件结束为止,也可以使用#undef来提前中止宏的作用范围。宏定义允许嵌套。定义有参数宏时应注意:宏名与形参表的圆括号之间不能有空格,否则会导致错误;在宏定义中,字符串内的形式参数最好用括号括起来,以避免错误。


       文件包含预处理命令#include把指定源文件的全部内容包括到当前源程序文件中。一个#include只能包含一个文件,要包含多个文件,需要使用多个#include命令。文件包含命令中的文件名既可以用尖括号也可以用双括号括起来,它们的区别在于查找指定文件的位置不同。尖括号只在缺省目录里找指定文件,缺省目录是由用户设置的编程环境决定的。双引号则先在源程序文件所在的当前目录里查找指定文件,如果没有找到再到缺省目录里找。如果指定文件与当前编写的源程序处在同一个目录里,就必须使用双引号来包含该文件,否则编译程序时编译器就会报告找不到指定的头文件。


       一般情况下,源程序中所有的行都被编译。有时希望其中一部分内容只在某个条件成立或不成立时才去编译,也就是对一部分内容指定编译的条件,这就是条件编译。条件编译总共有6种使用范式:


       (1) 范式一:


#ifndef 标识符


程序段1


#endif


含义:如果没有定义标识符,就编译程序段1,否则不编译该程序段。这里的程序段1既可以是语句组,也可以是命令行。


(2) 范式2


#ifndef 标识符


程序段1


#else


程序段2


#endif


含义:如果没有定义标识符,就编译程序段1,否则编译程序段2


(3) 范式2


#ifdef 标识符


程序段1


#endif


含义:如果定义了标识符,就编译程序段1,否则不编译该程序段。


(4) 范式4


#ifdef 标识符


程序段1


#else


程序段2


#endif


含义:如果定义了标识符,就编译程序段1,否则编译程序段2


(5) 范式5


#if 表达式


程序段1


#endif


含义:如果表达式成立,就编译程序段1,否则不编译该程序段。


(6) 范式6


#if 表达式


程序段1


#else


程序段2


#endif


       含义:如果表达式成立,就编译程序段1,否则编译程序段2


39、声明一个结构体也是一个C语言语句,因此需要以分号作为该语句的结束。声明结构体时漏写分号是一种常见的语法错误。声明了一个结构体,相当于构造了一个新的数据类型,此时系统并不为它分配内存空间,只有定义了结构体类型的变量,系统才为该变量分配内存空间。


40、内存的4字节对齐问题,参考下面一段程序进行体会:


#include<stdio.h>


 


struct student_1


{


       char name[20];


       int  age;


       char sex;


       char phone[15];


};


 


struct student_2


{


       char name[20];


       int  age;


       char sex;


       char phone[16];


};


 


int main()


{


       struct student_1 gujie;


       struct student_2 wanghaiqing;


       printf("%d\n",sizeof(gujie));


       printf("%d\n",sizeof(wanghaiqing));


}


输出为:


40


44


41、注意:只能引用结构体变量中的各个成员,而不能引用整个结构体变量。


42、引用结构体变量中的成员的一般方式为:


结构体变量.成员名


       .”是成员运算符,用于取得结构体中的成员,它在所有运算符中优先级最高。


       结构体中各个成员按顺序连续存放在内存中,结构体指针保存的值是它所指向的结构体变量所占内存的首地址。对于指针,访问它所指向的结构体的成员一般形式为:


       指针->结构体成员


43、共用体把几种不同数据类型的变量存放在同一块内存里。共用体中的变量共享一块内存,但在某一时刻只能在其中存放一个成员变量,共用体中起作用的成员是最后一次被存入的数据。共用体的长度取决于其成员的最大长度。共用体也有字节对齐情况。


44、不能把共用体变量作为函数参数,也不能使函数返回共用体变量,但可以使用指向共用体变量的指针。


45、使用typedef:软件开发中,除了使用C语言提供的标准类型名和声明的结构体、共用体、指针外,还可以使用typedef声明新类型名来代替已有的类型名。


例如:typedef int INT


声明之后,INTint就是等价的。可以在声明结构体类型时使用typedef


typedef struct


{


       int year


int month;


char day;


}DATE;


       声明新的结构体类型为DATE,之后就可以使用DATE来定义变量。


46、对于结构体和共用体,对齐规则是以成员中所占字节最多的那个基本数据类型进行对齐的,即如果成员中有double型数据,那么系统在为结构体和共用体分配内存空间时是8字节对齐的。在32位机器中,charintfloatdouble所占用的内存空间分别为1448个字节。值得注意是,如果在对齐数据类型之前或之后定义的数据所占内存空间之和没有达到对齐数据类型的长度,那么应该按对齐数据类型的长度为其分配空间。例如:


#include<stdio.h>


 


union data1


{


       double a1;


       int    a2;


       char   a3;


       char   a4[9];


}data1;


 


struct data2


{


       double b1;


       int    b2;


       char   b3;


       char   b4[9];


}data2;


 


struct data3


{


       char   c1;


       double c2;


       char   c3;


}data3;


 


struct data4


{


       char   d1;


       char   d2;


       double d3;


}data4;


 


int main()


{


       printf("%d %d %d %d\n",sizeof(data1),sizeof(data2),sizeof(data3),sizeof(data4));


       return 0;


}


输出为:16 24 24 16

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
7
1
2
3
4
5
6
7
8
9
0
关闭 站长推荐上一条 /6 下一条