c语言几个,几个C语言知识点

66b52468c121889b900d4956032f1009.png

8种机械键盘轴体对比

本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?

重新整理以前的笔记,基本来自《C语言深度解剖》。

原码/反码/补码

原码:原码就是这个数本身的二进制形式,其中最高位为符号位。

补码:在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理。

反码:正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。

求补码的方法:整数或零,则补码等于原码,负数则补码等于除符号位外,各位取反加一

求反码的方法:正数,反码与原码相同,负数,对其原码逐位取反,但符号位除外,符号位还是一

在计算机系统中,数值一律用补码来表示。

问题1:

int main()

{

char a[1000];

int i;

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

{

a[i] = -1-i;

}

printf("%d",strlen(a));

return 0;

}

以上代码输出为255

问题2:

char a = -300,求 int a

300的原码:1 0010 1100

取反:1101 0011

加一:1101 0100

300的补码:1101 0100

符号位:1

求原码:101 0100

取反:010 1011

加一:010 1100

求得:-44

问题3:

int i = -20;

unsigned j = 10;

i+j的值为多少?为什么?

问题4:

下面的代码有什么问题?

unsigned i ;

for (i=9;i>=0;i--)

{

printf("%un",i);

}

数据类型基本类型 - 数值类型、字符类型

构造类型 - 数组、结构体、共用体、枚举类型

指针类型

空类型

常用数据类型在32位和64位CPU上的字节数比较:

测试进程:

printf("char[%d], char*[%d], short int[%d], int[%d], unsigned int[%d], float[%d], double[%d], long[%d], long long[%d], unsigned long[%d]n",

sizeof(char),sizeof(char *),

sizeof(short int),sizeof(int),sizeof(unsigned int),

sizeof(float),sizeof(double),

sizeof(long),sizeof(long long),sizeof(unsigned long));

不同CPU类型的输出结果:

x86_64:char[1], char*[8], short int[2], int[4], unsigned int[4], float[4], double[8], long[8], long long[8], unsigned long[8]

i686:

总结:很明显的比较结果,指针和长整形由4个字节升为8个字节

32个关键字

举例:

register - 声明寄存器变量

const - 声明只读变量

volatile - 说明变量在进程执行中可被隐含地改变。这个关键字声明的变量,编译器对访问该变>量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。

分析:

一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。(对Java来说:Java内存模型告诉我们,各个线程会将共享变量从主内存中拷贝到工作内存,然后执行引擎会基于工作内存中的数据进行操作处理。线程在工作内存进行操作后何时会写到主内存中?这个时机对普通变量是没有规定的,而针对volatile修饰的变量给java虚拟机特殊的约定,线程对volatile变量的修改会立刻被其他线程所感知,即不会出现数据脏读的现象,从而保证数据的“可见性”。)

下面是volatile变量的几个例子:并行设备的硬件寄存器(如:状态寄存器)

一个中断服务子进程中会访问到的非自动变量(Non-automatic variables)

多线程应用中被几个任务共享的变量

回答不出这个问题的人是不会被雇佣的。我认为这是区分C进程员和嵌入式系统进程员的最基本的问题。嵌入式系统进程员经常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。 假设被面试者正确地回答了这是问题(嗯,怀疑这否会是这样),我将稍微深究一下,看一下这家伙是不是直正懂得volatile完全的重要性。

有如下3个问题:一个参数既可以是const还可以是volatile吗?解释为什么。

一个指针可以是volatile 吗?解释为什么。

下面的函数有什么错误:

int square(volatile int *ptr)

{

return *ptr * *ptr;

}

下面是答案:是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为进程不应该试图去修改它。

是的。尽管这并不很常见。一个例子是当一个中断服务子进程修改一个指向一个buffer的指针时。

这段代码的有个恶作剧。这段代码的目的是用来返指针ptr指向值的平方,但是,由于ptr指向一个volatile型参数,编译器将产生类似下面的代码:

int square(volatile int *ptr)

{

int a,b; a = *ptr;

b = *ptr;

return a * b;

}

由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:

long square(volatile int *ptr)

{

int a; a = *ptr;

return a * a;

}

extern: 说明变量是在其他文档中声明(也可以看作是引用变量)

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

函数参数的声明举例:void func(int i,char c)

定义声明最重要的区别:定义创建了对象,并为这个对象分配了内存,声明没有分配内存

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

register变量必须是能被CPU寄存器所接受的类型。意味着register变量必须是一个单个的值,并且其长度应小于或等于整形的长度。而且register变量可能不存在内存中,所以不能用取址运算符“&”来获取register变量的地址。比如说,32位的CPU,最多是4个字节,整形和长整形都是占4个字节的数据类型。

注意:register变量只是对编译器的建议,编译器并不一定会将该变量作为register变量。

static关键字作用修饰变量

静态区是分配静态变量、全局变量空间的;初始化的全局变量放在数据段;局部变量放在栈;未初始化的全局变量放在bss段。

从C进程运行的角度看,内存几大部分:静态存储区、堆区和栈区。

静态存储区:内存在进程编译的时候就已经分配好,这块内存在进程的整个运行期间都存在。它主要存在静态数据、全局数据和常量。

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

#include int a = 0;//全局初始化区 char *p1;//全局未初始化区 void main(void)

{

int b;//栈 char s[] = "abc";//栈 char *p2;//栈 char *p3 = "123456";//123456 在常量区,p3在栈上 static int c = 0;//全局(静态)初始化区 p1 = (char *)malloc(10);//堆 p2 = (char *)malloc(20);//堆 p1 = "123456";//123456 在常量区,编译器将p1与p3所指向的“123456 ”优化成同一个地方 }

全局变量、局部变量、静态全局变量、静态局部变量的区别,如下:从作用域看全局变量具有全局域。全局变量只需在一个源文档中定义,就可以作用于所有的源文档。当然,其他不包括全局变量定义的源文档需要用extern关键字再次声明这个全局变量。

静态局部变量具有局部作用域。它只被初始化一次,自从第一次初始化直到进程结束都一直存在。它和全局变量的区别在于全局变量对所有的函数都是可见的,而静态局部变量只对定义自己的函数体始终可见。

局部变量也只有局部作用域,他是自动对象,他在进程运行期间不是一直存在,而是只在函数执行期间存在,函数的一次调用结束后,变量就被撤销,其所占用的内存也被收回。

静态全局变量(其他文档即使使用extern声明也没法使用它)也具有全局作用域,它与全局变量的区别在于如果进程包含多个文档的话,他作用于定义它的文档里,不能作用到其他文档里,即被static关键字修饰过的变量具有文档作用域。这样即使两个不同的源文档都定义了相同的静态全局变量,它们也是不同的变量。

从分配内存空间看

全局变量、静态全局变量、静态全局变量都在静态存储区分配空间,而局部变量在栈分配空间。

把局部变量改变为静态变量后是改变了它的存储方式,即改变了它的生命周期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围,因此static这个说明符在不同的地方起的作用是不同的。

注意:

对于静态局部变量的理解:若全局变量仅在单个函数中使用,则可以将这个变量修改为改函数的静态局部变量

由于被static修饰的变量总是存在内存的静态区,所以即使这个函数运行结束,这个静态变量的值还是不会被销毁,函数下次使用时仍然能用到这个值

直观的例子:

int k,ii = 0;

static int j;

void func1(void)

{

static int i = 0;

i++;

ii++;

printf("i = %dn",i);

printf("ii = %dn",ii);

}

void func2(void)

{

j = 0;

j++;

printf("j = %dn",j);

}

int main()

{

for(k=0;k<10;k++)

{

func1();

func2();

sleep(1);

}

return 0;

}

修饰函数

函数前加static使得函数成为静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文档(所以又称为内部函数)。

C++里对static赋予了第三个作用(如果成员声明为static,可以在外部直接访问)静态数据成员静态数据成员是该类的所有对象所共有的。对该类的多个对象来说,静态数据成员只分配一个内存,供所有对象共用

静态数据成员存储在全局数据区。静态数据成员定义时要分配空间,所以不能在类声明中定义

静态成员函数静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数

非静态成员函数可以任意地访问静态成员函数和静态数据成员

静态成员函数不能访问非静态成员函数(不包括构造函数)和非静态数据成员

sizeof关键字

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