战胜C语言中令人头疼的问题

C语言一共32个关键字,下面一一列出:

 

1.auto声明自动变量

在默认情况下,编译器默认所有变量都是auto

2.int声明整型变量

3.double声明双精度变量

4.long声明长整型变量

5.char声明字符型变量

6.float声明浮点型变量

7.short声明短整型变量


8.signed声明有符号类型变量

9.unsigned声明无符号类型变量

最高位如果是1,表明这个数是负数,其值为除最高位以外的剩余位的值添上这个“-”号;

如果最高位是0,表明这个数是正数,其值为除最高位以外的剩余位的值。

一个32位的signed int类型整数其值表示法范围为:-2(31)~2 (31)-1;

8位的char类型数其值表示的范围为-2(7)~2 (7)-1;

 一个32位的unsigned int类型整数其值表示法范围为:-2(32)~2 (32)-1;

8位的char类型数其值表示的范围为-2(8)~2 (8)-1;

 编译器默认变量都是signed


10.struct声明结构体变量

11.union声明联合数据类型

12.enum声明枚举类型


13.static

两个作用

1.修饰变量

静态全部变量:

全局变量本来就是静态的,不同的是,静态全局变量,作用域只局限于被定义的文件内,其他文件加extern也无法访问;更准确地说,作用域只局限与本文件被定义处到文件结尾,本文件定义之前的代码也无法访问。

静态局部变量:

作用域仅限于定义的本函数内,其他函数无法调用,因为静态变量存放在静态区,所以当函数运行完,静态变量的值也不会被销毁,函数下次运行还会用到它。

总结一下:static改变了全局变量的作用域,改变了局部变量的生存期

2.修饰函数

static修饰的函数改变了函数的作用域,只作用于本文件内,所以也称为"内部函数",使用内部函数,不用担心自己写的函数和别人写的函数重名。


14.switch用于开关语句

15.case开关语句分支

16default开关语句中的“其他”分支


17.break跳出当前循环

(1) 只能在循环体内和switch语句体内使用break语句。

(2) 当break出现在循环体中的switch语句体内时,其作用只是跳出该switch语句体。

(3) 当break出现在循环体中,但并不在switch语句体内时,则在执行break后,跳出本层循环体。
(4) 只能用于循环语句或switch语句中,用于结束最接近的一层循环


18.register声明寄存器变量

这个关键字请求编译器尽可能的将变量存在CPU内部寄存器中而不是通过内,存寻址访问以提高效率。注意是尽可能,一个CPU的寄存器也就那么几个或几十个,你要是定义了很多很多register变量,它累死也可能不能全部把这些变量放入寄存器。

虽然寄存器的速度非常快,但是使用register修饰符也有些限制的:

register变量必须是能被CPU寄存器所接受的类型。意味着register变量必须是一个单个的值,并且其长度应小于或等于整型的长度。而且register变量可能不存放在内存中,所以不能用取址运算符“&”来获取register变量的地址


19.const声明只读变量


20.volatile说明变量在程序执行中可被隐含地改变

volatile的意思是说明这个变量是可能被别的程序或者本程序的其他线程修改的,这样编译器就不能优化它,每次读取都从地址中获取。如果不这样声明的话编译器可以把它缓冲在寄存器中的,这样别的程序修改了它,而寄存器里面的值却是原先的,会发生你不想要的结果。而上面三种情况都是这种可能在本程序或者本线程外被修改的情况,所以要加它。一般用于下面3种情况。
1). 并行设备的硬件寄存器(如:状态寄存器) 
2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables) 
3). 多线程应用中被几个任务共享的变量 
volatile关键字的作用在于提醒编译器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份;通过这种方式也就给了volatile定义的变量被线程或中断服务子程序共享使用的能力,否则即使变量在中断中修改了,终端返回后读到的值仍然是修改之前的值,这样的程序会出现这样那样不可预知的bug

21.typedef用以给数据类型取别名

注意#define 与typedef的区别

嵌入式中考虑到各种平台的兼容性用typedef

typedef unsigned int uint

define 只是在预处理时宏定义单纯的替换,,而typedef是起别名

举个例子:

 #define INT1 int*

typedef  int* INT2

INT1  i1,i2;  // 定义一个指针变量 i1和整数变量12

INT2 i3,i4,  //  定义两个指针变量 i3,i4

 

22.extern声明变量是在其他文件中声明

23.return子程序返回语句

24.void声明函数无返回值或无参数,声明空类型指针


25continue结束当前循环,开始下一轮循环

1) continue语句continue语句的一般形式为:contonue;
      (2) 其作用是结束本次循环,即跳过本次循环体中余下尚未执行的语句,接着再一次进行循环的条件判定
      (3) 注意:执行continue语句并没有使整个循环终止。在while和do-while循环中,continue语句使得流程直接跳到循环控制条件的测试部分,然后决定循环是否继续进行。
      (4) 在for 循环中,遇到continue后,跳过循环体中余下的语句,而去对for语句中的“表达式3”求值,然后进行“表达式2”的条件测试
       最后根据“表达式2”的值来决定for循环是否执行。在循环体内,不论continue是作为何种语句中的语句成分,都将按上述功能执行,这点与break有所不同。


26.do循环语句的循环体

27.while循环语句的循环条件

28.if条件语句

29.else条件语句否定分支

30.for一种循环语句

31.goto无条件跳转语句


33.sizeof计算对象所占内存空间大小

 inti=0;(32位系统下测试)

A),sizeof(int);B),sizeof(i);C),sizeof int;D),sizeof i;

A),B)的值为4。那C)的呢?D)的呢?

通过调试得知D的结果也为4,c的答案是错的。

由此轻易得出sizeof绝非函数

sizeof在计算变量所占空间大小时,括号可以省略,而计算类型(模子)大小时不能省略


数据结构的栈和堆

  首先在数据结构上要知道堆栈,尽管我们这么称呼它,但实际上堆栈是两种数据结构:堆和栈。堆和栈都是一种数据项按序排列的数据结构。

栈就像装数据的桶或箱子
  我们先从大家比较熟悉的栈说起吧,它是一种具有后进先出性质的数据结构,也就是说后存放的先取,先存放的后取。这就如同我们要取出放在箱子里面底下的东西(放入的比较早的物体),我们首先要移开压在它上面的物体(放入的比较晚的物体)。
堆像一棵倒过来的树
而堆就不同了,堆是一种经过排序的树形数据结构,每个结点都有一个值。通常我们所说的堆的数据结构,是指二叉堆。堆的特点是根结点的值最小(或最大),且根结点的两个子树也是一个堆。由于堆的这个特性,常用来实现优先队列,堆的存取是随意,这就如同我们在图书馆的书架上取书,虽然书的摆放是有顺序的,但是我们想取任意一本时不必像栈一样,先取出前面所有的书,书架这种机制不同于箱子,我们可以直接取出我们想要的书。

一个由c/C++编译的程序占用的内存分为以下几个部分:
1、栈区(stack)— 由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。

2、堆区(heap) — 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。

3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后由系统释放。

4、文字常量区   —常量字符串就是放在这里的。程序结束后由系统释放。

5、程序代码区—存放函数体的二进制代码。


 指针数组 数组指针 指针函数 函数指针

int   *p[4];         //指针数组。  是个有4个元素的数组, 每个元素的是指向整型的指针。(数组的每个元素都是指针)
int   (*p)[4];       //数组指针。 它是一个指针,指向有4个整型元素的数组。                (一个指针指向有4个整型元素的数组)
int *func(void);     //指针函数。 无参函数, 返回整型指针。             (函数的返回值为int*)    
int (*func)(void);   //表示函数指针,可以指向无参, 且返回值为整型指针的函数。      (函数的返回值为int)


面试题:a 和&a 有什么区别

    请写出以下代码的打印结果,主要目的是考察a 和&a 的区别。

    #include<stdio.h> 
    void main( void ) 
    { 
        int a[5]={1,2,3,4,5}; 
        int *ptr=(int *)(&a+1);

        printf("%d,%d",*(a+1),*(ptr-1)); 
        return; 
    }

    输出结果:2,5。 
    注意:数组名a 可以作数组的首地址,而&a 是数组的指针。思考,将原式的int *ptr=(int *)(&a+1);

改为int *ptr=(int *)(a+1);时输出结果将是什么呢?

原文地址:https://www.cnblogs.com/summer-xwq/p/4147568.html