C语言的一些坑

变量的声明有两种情况:

1、一种是需要建立存储空间的。例如:int a 在声明的时候就已经建立了存储空间。
2、另一种是不需要建立存储空间的,通过使用extern关键字声明变量名而不定义它。 例如:extern int a 其中变量 a 可以在别的文件中定义的。
除非有extern关键字,否则都是变量的定义。

左值(lvalue):指向内存位置的表达式被称为左值(lvalue)表达式;
右值(rvalue):术语右值(rvalue)指的是存储在内存中某些地址的数值。

3、存储类定义 C 程序中变量/函数的范围(可见性)和生命周期。这些说明符放置在它们所修饰的类型之前。下面列出 C 程序中可用的存储类:auto 只能用在函数内,即 auto 只能修饰局部变量。register 存储类用于定义存储在寄存器中而不是 RAM 中的局部变量;static 存储类指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。因此,使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。
4、extern 存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。extern 修饰符通常用于当有两个或多个文件共享相同的全局变量或函数的时候。
5、传值调用,该方法把参数的实际值复制给函数的形式参数。在这种情况下,修改函数内的形式参数不会影响实际参数。引用调用,通过指针传递方式,形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作。默认情况下,C 使用传值调用来传递参数。一般来说,这意味着函数内的代码不能改变用于调用函数的实际参数。
6、/* 函数声明 *///作用是可以将函数的实现放到main后面定义,严格遵守先声明再使用的规则
7、全局变量与局部变量在内存中的区别:全局变量保存在内存的全局存储区中,占用静态的存储单元;
局部变量保存在栈中,只有在所在函数被调用时才动态地为变量分配存储单元。当局部变量被定义时,系统不会对其初始化,您必须自行对其初始化。定义全局变量时,系统会自动对其初始化

8、另外,C 不支持在函数外返回局部变量的地址,除非定义局部变量为 static 变量。
9、所有指针的值的实际数据类型,不管是整型、浮点型、字符型,还是其他的数据类型,都是一样的,都是一个代表内存地址的长的十六进制数。不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同。为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针。NULL 指针是一个定义在标准库中的值为零的常量,这个运算会在不影响内存位置中实际值的情况下,移动指针到下一个内存位置
10、我们想要让数组存储指向 int 或 char 或其他数据类型的指针。下面是一个指向整数的指针数组的声明:int *ptr[MAX];
数组指针:意思是说这个指针存放着一个数组的首地址,或者说这个指针指向一个数组的首地址。
指针数组:意思是说这个数组的所有元素都是指针类型。
11、指向指针的指针是一种多级间接寻址的形式,int **var;能接受指针作为参数的函数,也能接受数组作为参数;C 语言不支持在调用函数时返回局部变量的地址,除非定义局部变量为 static 变量。
12、函数指针变量的声明:
typedef int (*fun_ptr)(int,int); // 声明一个指向同样参数、返回值的函数指针类型,fun_ptrshi指针函数
13、在 C 语言中,字符串实际上是使用 null 字符 '\0' 终止的一维字符数组。
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
依据数组初始化规则,您可以把上面的语句写成以下语句:
char greeting[] = "Hello";在使用不定长数组初始化字符串时默认结尾为 \0

14、struct 语句定义了一个包含多个成员的新的数据类型,struct 语句的格式如下:

    member-list
    member-list 
    member-list  
    ...
} variable-list ;

为了访问结构的成员,我们使用成员访问运算符(.)
定义指向结构的指针,方式与定义指向其他类型变量的指针相似,
struct Books *struct_pointer;struct_pointer = &Book1;
为了使用指向该结构的指针访问结构的成员,您必须使用 -> 运算符,
struct_pointer->title;

15、,C 语言又提供了一种数据结构,称为"位域"或"位段"。
所谓"位域"是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。

{

 位域列表

};
struct bs{
    int a:8;
    int b:2;
    int c:6;
}data;

位域的使用和结构成员的使用相同,其一般形式为:
位域变量名.位域名
位域变量指针->位域名

16、共用体是一种特殊的数据类型,允许您在相同的内存位置存储不同的数据类型。您可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。共用体提供了一种使用相同的内存位置的有效方式。

{
   member definition;
   member definition;
   ...
   member definition;
} [one or more union variables];

17、C 语言提供了 typedef 关键字,您可以使用它来为类型取一个新的名字;

typedef unsigned char BYTE;

define 是 C 指令,用于为各种数据类型定义别名,与 typedef 类似,但是它们有以下几点不同:

typedef 仅限于为类型定义符号名称,#define 不仅可以为类型定义别名,也能为数值定义别名,比如您可以定义 1 为 ONE。
typedef 是由编译器执行解释的,#define 语句是由预编译器进行处理的。

18、C 语言把所有的设备都当作文件。所以设备(比如显示器)被处理的方式与文件相同。以下三个文件会在程序执行时自动打开,以便访问键盘和屏幕。stdin、stdout、stderr(文件指针);char getchar(void) & putchar() 函数char * gets(char *s) & puts() 函数;int scanf(const char *format) 和 printf() 函数

19、C 预处理器不是编译器的组成部分,但是它是编译过程中一个单独的步骤。简言之,C 预处理器只不过是一个文本替换工具而已,它们会指示编译器在实际编译之前完成所需的预处理,所有的预处理器命令都是以井号(#)开头,别忘了#endif;宏延续运算符(\)一个宏通常写在一个单行上。但是如果宏太长,一个单行容纳不下,则使用宏延续运算符(\);字符串常量化运算符(#)
在宏定义中,当需要把一个宏的参数转换为字符串常量时,则使用字符串常量化运算符(#)

#define  message_for(a, b)  \
    printf(#a " and " #b ": We love you!\n");

标记粘贴运算符(##)宏定义内的标记粘贴运算符(##)会合并两个参数。它允许在宏定义中两个独立的标记被合并为一个标记
20、引用头文件相当于复制头文件的内容,#include 这种形式用于引用系统头文件。它在系统目录的标准列表中搜索名为 file 的文件;
如果一个头文件被引用两次,编译器会处理两次头文件的内容,这将产生错误。为了防止这种情况,标准的做法是把文件的整个内容放在条件编译语句中,如下:

ifndef HEADER_FILE

define HEADER_FILE

the entire header file file

endif

include "file"这种形式用于引用用户头文件。它在包含当前文件的目录中搜索名为 file 的文件。

21、强制类型转换是把变量从一种类型转换为另一种数据类型。(type_name) expression,注意的是强制类型转换运算符的优先级大于除法;常用的算术转换是隐式地把值强制转换为相同的类型
22、C 语言不提供对错误处理的直接支持,但是作为一种系统编程语言,它以返回值的形式允许您访问底层数据。在发生错误时,大多数的 C 或 UNIX 函数调用返回 1 或 NULL,同时会设置一个错误代码 errno,该错误代码是全局变量,表示在函数调用期间发生了错误。程序成功执行完一个操作正常退出的时候会带有值 EXIT_SUCCESS。在这里,EXIT_SUCCESS 是宏,它被定义为 0。
如果程序中存在一种错误情况,当您退出程序时,会带有状态值 EXIT_FAILURE,被定义为 -1
23、可变参数,函数 int func(int, ... ) 最后一个参数写成省略号,即三个点号(...),省略号之前的那个参数是 int,代表了要传递的可变参数的总数。为了使用这个功能,您需要使用 stdarg.h 头文件,该文件提供了实现可变参数功能的函数和宏。int demo(char msg, ... ) ,char 类型的可变参数。
24、C 语言为内存的分配和管理提供了几个函数。这些函数可以在 头文件中找到;
void *calloc(int num, int size); 返回void *指针,可以转换为任何类型的指针。
void free(void *address);
24、命令行参数,可以从命令行传值给 C 程序。这些值被称为命令行参数;命令行参数是使用 main() 函数参数来处理的,其中,argc 是指传入参数的个数,argv[] 是一个指针数组,指向传递给程序的每个参数。
int main( int argc, char argv[] ) argv[] 是一个指针数组,指向传递给程序的每个参数
argv[0] 存储程序的名称,argv[1] 是一个指向第一个命令行参数的指针,
argv[n] 是最后一个参数。如果没有提供任何参数,argc 将为 1,否则,如果传递了一个参数,argc 将被设置为 2。

*****字符串常量的本质表现是代表它的第一个字符的地址

你可能感兴趣的:(C语言的一些坑)