学习日记之c语言易错易考点1

1,a++、++a

a++  先赋值再自增

++a 先自增后赋值

使用以下代码区分两者的区别:

int main()
{
	//可以理解成  ++a 是先自增后使用
	int a = 8;
	int b = ++a;
	printf("a = %d   b = %d\n", a, b);//9  9

	// a++ 是先使用后自增
	a = 10;
	b = a++;
	printf("a = %d   b = %d\n", a, b);//9  8

	return 0;
}

if语句内的等号

在刚开始学习c语言中会经常犯的错误就是 在if判断语句中只写了一个等号,然后导致程序跑完后现象跟你所想的不一致而且编译器还不会报错,

此时可以将数字写到等号前面 如果是一个等号编译器就会识别报错,而且不会影响正常的使用。

break关键字:

break可以跳出循环的控制语句和switch的语句,切记不能跳出 if 的判断语句,不然也会出现比较隐蔽的错误。

static 关键字的作用:

a) static修饰局部变量会延长局部变量的生命周期,并且只在第一次调用函数时对这个局部变量进行初始化,后续在调用这个函数都不在进行初始化的操作。

b) 如果static修饰的局部变量没有初始化,存在.bss段,默认初始化为0

c) 如果使用static修饰的局部变量初始化,存在.data段

d) static修饰的局部变量只是延长了生命周期,访问依然只能在函数内进行访问。

static修饰全局变量或者函数表示在外部的源文件中不可以访问,只能在本文将中进行访问。

全局变量在静态存储区,局部变量在堆栈区

学习日记之c语言易错易考点1_第1张图片

register:寄存器类型

1,寄存器数量有限使用频率不高,

2,寄存器变量不可以取地址因为没有地址

3,只用于快速访问的变量,如计数器。

const:

const 用来修饰指针,有下面四种写法

要看 const 在 * 的左边还是右边。如果是在左边,表示修饰的是 *p ,表示不能通过指针修改指向的内容。如果是在右边,表示修饰的是 p, 表示指针的指向不能修改

    const int *p;
	int const *p; 前两种写法是一样的。
	int * const p;
	const int * const p;

extern:

修饰全局变量或者函数,表示这个函数或者变量在其他文件进行定义,通常用于两个或者多个文件共享的全局变量或者函数时的场景。

引用一个定义过的全局变量

可以引用头文件的方式,也可以使用extern关键字,,如引用头文件的方式,假如全局变量写错了在编译期间就会报错,而用extern关键字 在编译不会出错在链接部分会出错。

static 声明的全局变量、局部变量、函数与普通的全局、局部、函数有什么区别?

static 声明的全局变量

        与

普通的全局变量

相同点:都是全局变量都存储在静态区,存储方式相同,

不同点:普通全局变量作用域是整个源程序,当一个源程序是由多个源文件组成时,普通全局变量在各个源文件都是有效的。而经过static声明后变成静态全局变量后限制了作用域,只在定义变量的源文件有效,在同一个源程序下不同的源文件不可以使用,只能成为本源文件的全局变量即使外部声明extern也不可以并且只初始化一次,正因如此考虑数据安全性可以避免在其他源文件中引起的错误。总得来说就是作用域不同


static 的局部变量

        与

普通局部变量

static 的局部变量增加了生命周期,改变了存储方式,直到程序运行结束才会被释放,并且下一次会依据上一次的值。

而普通的局部变量在程序结束或者函数结束后就已经释放掉了 。


static 的函数

        与

   普通函数

被static修饰后就变成只在本源文件使用的内部函数,并且在该源文件内说明和定义,不能被其他文件调用

c语言的编译过程:

整体分为4个过程:预处理-->编译-->汇编-->链接

预处理

头文件的展开、宏定义的替换、注释的删除

在Linux-Ubuntu中可以使用如下命令生成后缀名为 .i的文件进行查看

gcc -E hello.c -o hello.i

编译

词法分析、语法分析,是用来查错的

如果无误,会生成对应的汇编文件,如果有误的话无法进入下一个阶段,会在命令行是会打印出错误信息。gcc -S hello.i -o hello.s 会生成后缀名为 .s的文件为汇编文件。

汇编

将汇编文件生成计算机能识别的二进制文件

通过 gcc -c hello.s -o hello.o

链接

链接库文件,生成对应的可执行文件

通过 gcc hello.o -o hello(可以是自定义名字)

#define 和 typedef 的区分

#define:

        首先凡是以 # 号开头的都是预处理命令,当然#define 与常用的#include一样也不例外,#define 定义一个标识符来表示一个常量,这个标识符遵循标识符命名规则。作为宏定义使用。在预处理时进行替换被称为宏定义。

#include

#define aaa  1
#define bbb  2


int main()
{
	printf( "aaa 的值: %d\n", aaa);
   	printf( "bbb 的值: %d\n", bbb);
	return 0;
}

typedef:

        重定义简单来说就是按照定义变量的方式,把变量名换上新类型名,并在最前面加上 typedef 就声明了新类型名代表原来的类型。并且typedef只对已存在的类型指定一个新的类型名,没有创造新的类型名,并且用来声明数组类型、指针类型、结构体、共用体类型时变得十分方便。

typedef int NUM[5];
NUM a;//就相当于定义了 int a[5]

两者的区分与注意项:

两者在表面上看似相同,但是实质上是不同的,#define是在预处理阶段处理的,只是简单的字符串替换操作,而typedef是在编译阶段处理的,是采用定义一个变量的方式去定义变量。宏定义后面是不能加分号的,而重定义typedef是必须加的。

使用typedef有利于程序的通用与移植,有时程序会依赖硬件特性,此时体现出便捷性。有的计算机系统 int占用两个字节,但有的是占用4个字节,如果将一个c程序从4字节的移植到2字节的时候,一般的办法是将int改成long,如果有多处定义就需要一处一处都需要改变,此时可以使用typedef int A 替代int ,在移植的时候只需要改变typedef long A 就可以了。---参考了大神们的解释

typedef:

        1> 将变量的定义前边加一个typedef, 此时变量名等价于原来的数据类型。

        2> 结尾必须加“;”

        3> 新的类型起别名时一般以_t结尾

        4> typedef起别名时参与编译过程的

在使用时需注意:

#define  intp_t  int *  
    intp_t  p, q;  // p是指针  q是整型变量 只简单替换了两者。
         	==> int *p, q; 
        typedef  int * intp_t
        intp_t  p, q;  // p和q都是指针

strlen 和 sizeof

strlen

计算字符串长度,不包括 '\0'。在打印的时候用%ld

sizeof

计算数据在内存的所占空间的大小,与定义时的数据类型有关,计量单位是字节,int 类型为4个字节、char类型为1个字节等。sizeof他是一个关键字,不是一个函数,可以用来计算类型或者变量占用的内存空间的大小,返回值结果是以 字节 为单位的。32为系统,返回的是 int %d

64为系统,返回的是 long %ld

在多文件编程的时候避免头文件重复包含

        头文件内容以 led.h 为例,如果宏没有定义以下内容就进行定义,如果已经包含了就不再重复定义包含。

#ifndef  __LED_H__
#define  __LED_H__
    //内部头文件代码
#endif 

结构体与共用体(联合体)的区别

结构体变量所占内存内存长度是各个成员内存长度之和,每个成员分别占有自己的内存单元。而共用体(联合体)变量所占的内存长度等于最长的成员长度。

        在以下代码内 a,b,c各占四个字节,如果换成结构结构体4+1+4。相比之下后者更加节省空间,空间使用效率更高

union{
    int i;
    char j;
    float k;
}a,b,c;

你可能感兴趣的:(c语言)