C语言深度解剖_121113

合集下载

c语言深度剖析

c语言深度剖析

c语言深度剖析
C语言是一门广泛应用于计算机编程领域的高级编程语言,它的设计目标是提供一种能够以简洁的方式编写系统软件的语言。

C语言的出现极大地推动了计算机科学的发展,成为了现代计算机编程的基础。

在深度剖析C语言时,我们需要从以下几个方面进行分析:
1. 语言特性
C语言的语言特性包括数据类型、运算符、控制语句、函数等。

其中,数据类型是C语言的基础,包括整型、浮点型、字符型等。

运算符包括算术运算符、关系运算符、逻辑运算符等。

控制语句包括条件语句、循环语句等。

函数是C语言的重要特性,它可以将程序分解为多个模块,提高程序的可读性和可维护性。

2. 内存管理
C语言的内存管理是其最为重要的特性之一。

C语言中的内存分为栈、堆、全局变量等。

程序员需要手动管理内存,包括内存的分配和释放。

如果内存管理不当,会导致内存泄漏、内存溢出等问题,严重影响程序的稳定性和性能。

3. 指针
指针是C语言的重要特性之一,它可以让程序员直接访问内存中的
数据。

指针可以用于数组、函数、结构体等。

指针的使用需要注意指针的类型、指针的初始化、指针的运算等问题。

4. 预处理器
C语言的预处理器是其独特的特性之一,它可以在编译之前对源代码进行处理。

预处理器可以用于宏定义、条件编译等。

预处理器的使用需要注意宏定义的作用域、宏定义的参数等问题。

深度剖析C语言需要对其语言特性、内存管理、指针、预处理器等方面进行全面的分析和理解。

只有深入了解C语言的特性和使用方法,才能更好地应用C语言进行编程,提高程序的质量和效率。

C语言深度解剖读书笔记

C语言深度解剖读书笔记

C语言深度解剖读书笔记之——C语言基础测试题前几天天看到这本书,感觉不错,在看之前,先做了后面的习题,结果只得了60多分,一直以为自己的基础还是不错的,做完后对了答案后,感觉自己的自信心一下全没有了,不过遇到问题解决问题,我用了2天时间好好研读了这本书,感觉真不错。

虽然感觉都是一些基础的知识,但是我读的还是津津有味,感觉收获蛮多的,感谢这本书的作者陈正冲。

呵呵,说来我本科专业和这位大牛还是同一个专业呢,呵呵。

不是只有计算机科班出身的才能学好编程,知真正的高手都是自学的。

今天就把我当时做错的题目和认为比较好的题目一个个写出来。

再次分析下如果我在哪家公司遇到类似这种题目我会感觉这家公司出题很有水平,重基础,真正理解C 语言的人才能得高分。

注重细节,知其然知其所以然。

题目1.下面代码有什么问题,为什么?[cpp]view plaincopyprint?1.#include <iostream>ing namespace std;3.4.int _tmain(int argc, _TCHAR* argv[])5.{6.char string[10],str1[10];7.int i;8.for (i=0;i<10;i++)9.{10.str1[i] = 'a';11.}12.strcpy(string,str1);13.cout<<string<<endl;14.system("pause");15.return 0;16.}运行的时候回出现下面情况:error1.exe 中的0xcccc6161 处未处理的异常: 0xC0000005: Access violation做这个题目的时候,我也知道字符串strcpy是以'\0'为结束标识的。

会产生数组越界,但是表达不清楚。

答案:运行到strcpy的时候可能会产生内存异常。

C语言详细教程(完整版)ppt课件

C语言详细教程(完整版)ppt课件
. C Programming Language
教学目的:掌握“文化基础”中的相关概 念,明确学习方法,了解C语言基本知识。
教学要求:明确本课程的目标及学习方法, 复习“文化基础”中与C语言相关的知识: 数制、编码、计算机系统组成,了解算法 的概念及表示、C语言及标识符、C语言基 本结构。
学时:2学时
输出AVER的值
.
A
C Programming Language
结束
[例1.2] 输出一个数的绝对值。
开始 输入 X
输入 X N X>=0吗? Y
N X>=0吗? Y
输出 -X 输出 X
输出 -X
输出 X
结束
. C Programming Language
[例1.3] 输入10个 数,把其 中的正数 输出。
程序语言发展现状程序语言发展现状programminglanguage三翻译方式三翻译方式高级语言源程序高级语言源程序目标程序目标程序codecode翻译翻译programminglanguage用高级语言用高级语言书写的源程序书写的源程序用高级语言用高级语言书写的源程序书写的源程序机器指令机器指令程序程序机器指令机器指令程序程序函数函数库库函数函数库库编译程序编译程序编译编译用用高级语言高级语言书写的书写的源程序源程序用高级语言高级语言书写的书写的源程序源程序执行结果执行结果执行结果执行结果解释程序解释程序函数函数库库函数函数库库解释并解释并执行执行programminglanguage用计算机解决问题的基本过程
. C Programming Language
1.1 引言 1.2 算法和程序设计初步 1.3 C语言简介 1.4 集成开发环境TurboC 2.0简介

C 语言深度解剖重点总结(经典)

C 语言深度解剖重点总结(经典)

《C 语言深度解剖》总结(陈正冲编著)1.register关键字请求编译器尽可能的将变量存储在CPU内部寄存器中而不是内存中以提高访问效率。

数据从内存中取出来首先放到寄存器中,然后CPU再从寄存器中读取数据来进行处理,处理完后同样通过寄存器放到内存中,CPU不直接和内存打交道。

Register的值必须是一个单个的值,并且其长度应小于或等于int的长度,而且register 变量可能不放在内存中,所以不能用取地址符(&)来获取register变量的地址。

2. #include <cstdlib>#include <iostream>using namespace std;int main(int argc, char *argv[]){char a[1000];for(int i=0; i<1000; i++)a[i] = -1 - i;cout << strlen(a) << endl;system("PAUSE");return EXIT_SUCCESS;}输出结果为:255先来了解下补码的知识:在计算机中,数值一律用补码来表示(存储),主要原因是使用补码,可以将符号位和其它位统一处理,同时,减法也可以按加法来处理,两外,两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位被舍去。

整数的补码和其原码一致,负数的补码:符号位为1,其余位为该数绝对值的原码按位取反,然后整个数加1.于是,for()循环中,当i = 255时,a[255] = -256, 由于char类型的只能表示-128~127之间的数,所以-256已经发生了溢出,只将最低8位赋给a[255], -256的补码的低8位为0,所以a[255] = 0, 也就是字符串的结尾符’\0’的ascii值,当用strlen()计算a的长度时,遇到a[255]时停止,于是strlen(a) = 255; (a[0]~a[254])3. 下面输出:#include <iostream>#include <string>#include <bitset>using namespace std;int main(){//freopen("output.txt", "wt", stdout);int i = -20;unsigned j = 10;bitset<32> b(i + j);int res = i + j;cout << b << endl;cout << hex << i + j << endl;cout << dec << res << endl;system("PAUSE");return 0;}输出结果:11111111111111111111111111110110fffffff6-10分析:当表达式中既有signed和unsigned时,计算结果为unsigned类型的,所以i + j的结果也是unsigned类型的,i + j = -10, -10的补码可以按照上面说的计算补码的介绍得出…如果把i + j的结果复制给int类型的,则-10的补码会被解析成有符号类型的,故res 的输出为-10;4.#include <iostream>#include <string>using namespace std;int main(){unsigned i;for(i=9; i>=0; i--)cout << "#####" << endl;system("PAUSE");return 0;}程序将无限的输出####, 因为i为unsigned类型的,永远>=0, 所以上面的for()是个死循环…5.如果函数没有返回值,那么声明为void 类型。

C语言深度解剖

C语言深度解剖

第一章关键字static1 修饰变量若在函数体内定义,则只适用本函数;若在函数体外定义,则从定义位置往后函数有效,若定义前函数向调用该变量,也得采用extern 声明。

备注:无论如何,static 声明的变量只能使用本文件中,其他文件即使用extern声明不但无法适用,编译器会报错。

2 修饰函数修饰函数时候,不是表达内存关系,而是声明该函数仅作用于本文件,其他文件调用会报错。

sizeof注意:1 sizeof是个关键字,而并非一个函数2 sizeof在测试变量长度时候其括号可以省略,但是测试数据类型(莫子)时候,则,不能省略。

例如:int i ; sizeof(i)==sizeof i ;但是sizeof(int) ; 合法,sizeof int ; 非法void1 定义:void valuble ;会报错void *valuble_pc;正确;2 空类型指针可以包容任何类型指针,但是任何类型指针却不可包容空类型指针。

void *valuble_pc;int *int_pc;valuble_pc = int_pc;//合法int_pc = valuble_pc;//非法3 void 最重要的应用是在函数返回值以及形参上。

一点需要明确:任何函数默认下的返回值都为int 类型。

return1 return 终结函数并可以返回相应类型值。

备注:return 返回函数指针时候,不要返回本函数局部变量地址(why?;自己想想)const1 const修饰的变量应该是一个只读变量,但并不意味着该变量就是常量:const int MAX_NO = 100;int recive[MAX_NO]; //编译器报错(Why?)2 const修饰变量可以放在变量类型之前,也可以放在变量类型之后const int i ;= = int const i ;3 修饰指针类型变量int dat1 = 9,dat2 =98;const int *pc1 = &dat1; //pc(地址可变);*pc(指针指向对象不可变)int const *pc2; //pc(地址可变);*pc(指针指向对象不可变)int * const pc3; //pc(地址不可变);*pc(指针指向对象可变)const int * const pc4; //pc(地址不可变);*pc(指针指向对象不可变)pc1 = &dat2 ; //合法*pc1 = dat2; //非法(Why?)(其他同理)4 修饰函数形参void fun(const int i){//code}表示:形参中,i的值不能改变;volatile1 个人理解:从改变编译器优化角度,因为编译器对于一般变量的读取都是编译器明确(很有把握该变量没有逃出编译器可见范围内更改值),这样,编译器在读取时候,如果编译器确定该变量之前读取到现今操作仍未改变,则编译器不再浪费时间的从先从变量地址获取该变量值,这些本来都是编译器优化的思想。

【高清实用版】C语言详解

【高清实用版】C语言详解
pow10 log log10 fabs sqrt
正弦函数 余弦函数 正切函数 反正弦函数 反余弦函数 反正切函数 指数函数(e的x次方) 指数函数(x的y次方)
指数函数(10的p次方) 对数函数ln(x) 对数函数log10x 求绝对值 计算平方根
double sin(double x) double cos(double x) double tan(double x) double asin(double x) double acos(double x) double atan(double x) double exp(double x)



变量-程序执行过程中,其值可以改变的量。 变量定义: 类型标识符 变量名列表; double x, y =3.1; //使用前需定义、赋初值
表2.3 常用转义字符及其含义
字符形式 转义字符的意义
\b \n \r \t \\ \‘ \‖
退格,将当前位置移到前一列 回车换行 回车,将当前位置移到本行开头 水平制表(跳到下—个tab位置) 反斜杠字符“\‖ 单引号字符 双引号字符

#include <stdlib.h> //其它常用函数 exit(0); //正常终止程序,值传给调用过程;为1则异常终止程序
上一张 下一张
表. 常用的数学函数(math.h)
上一张 下一张
类 别
函数名
作 用
函 数 原 型
三角 函数
指数 函数 对数 函数
求绝对值
sin cos tan asin acos atan exp pow

循环结构-在满足给定的条件下,反复执行某一组操作 while (表达式) do for (表达式1; 表达式2; 表达式3) 语句 语句 语句 while (表达式); 先判断,后执行 先执行,后判断 循环次数确定,先判断,后执行

C 语言深度解剖学习笔记

C 语言深度解剖学习笔记

C语言深度解剖学习笔记《C语言深度解剖》前言:如果本书上面的问题能真正明白80%,作为一个应届毕业生,肯怕没有一家大公司会拒绝你。

第一章关键字什么是定义?什么是声明?什么是定义:所谓的定义就是(编译器)创建一个对象,为这个对象分配一块内存并给它取上一个名字,这个名字就是我们经常所说的变量名或对象名。

但注意,这个名字一旦和这块内存匹配起来,它们就同生共死,终生不离不弃。

并且这块内存的位置也不能被改变。

一个变量或对象在一定的区域内(比如函数内,全局等)只能被定义一次,如果定义多次,编译器会提示你重复定义同一个变量或对象。

什么是声明:有两重含义,如下:第一重含义:告诉编译器,这个名字已经匹配到一块内存上了,下面的代码用到变量或对象是在别的地方定义的。

声明可以出现多次。

第二重含义:告诉编译器,我这个名字我先预定了,别的地方再也不能用它来作为变量名或对象名。

定义声明最重要的区别:定义创建了对象并为这个对象分配了内存,声明没有分配内存C语言标准定义的32个关键字关键字意义auto声明自动变量,缺省时编译器一般默认为autoint声明整型变量double声明双精度变量long声明长整型变量char声明字符型变量float声明浮点型变量short声明短整型变量这六个关键字代表C语言里的六种基本数据类型在32位的系统上short内存大小是2个byte;int内存大小是4个byte;long内存大小是4个byte;float内存大小是4个byte;double内存大小是8个byte;char内存大小是1个byte。

(注意这里指一般情况,可能不同的平台还会有所不同,具体平台可以用sizeof关键字测试一下)signed声明有符号类型变量unsigned声明无符号类型变量正负数:最高位如果是1,表明这个数是负数。

如果最高位是0,表明这个数是正数struct声明结构体变量不要认为结构体内不能放函数\union声明联合数据类型union只配置一个足够大的空间以来容纳最大长度的数据成员enum声明枚举类型成员都是常量,也就是我们平时所说的枚举常量(常量一般用大写)。

C语言深度解剖读书笔记

C语言深度解剖读书笔记

C语⾔深度解剖读书笔记开始本节学习笔记之前,先说⼏句题外话。

其实对于C语⾔深度解剖这本书来说,看完了有⼀段时间了,⼀直没有时间来写这篇博客。

正巧还刚刚看完了国嵌唐⽼师的C语⾔视频,觉得两者是异曲同⼯,所以就把两者⼀起记录下来。

等更新完这七章的学习笔记,再打算粗略的看看剩下的⼀些C语⾔的书籍。

本节知识:1.c语⾔中⼀共有32个关键字,分别是:auto、int、double、long、char、short、float、unsigned、signed、sizeof、extern、static、goto、if、else、struct、typedef、union、enum、switch、case、break、default、do、while、const、register、volatile、return、void、for、continue。

注意:define、include这些带#号的都不是关键字,是预处理指令。

2.定义与声明:定义是创建⼀个对象并为⽌分配内存。

如:int a;声明是告诉编译器在程序中有这么⼀个对象,并没有分配内存。

如: extern int a;3.对于register这个关键字定义的变量,不能进⾏取地址运算(&),因为对于x86架构来说,地址都是在内存中的,不是在寄存器中的,所以对寄存器进⾏取地址是没有意义的。

并且应该注意的是给register定义的变量,应该赋⼀个⽐寄存器⼤⼩要⼩的值。

注意:register只是请求寄存器变量,但是不⼀定申请成功。

4.关键字static:=对于static有两种⽤法:a.修饰变量:对于静态全局变量和静态局部变量,都有⼀个特点就是不能被作⽤域外⾯,或外⽂件调⽤(即使是使⽤了extern也没⽤)。

原因就是它是存储在静态存储区中的。

对于函数中的静态局部变量还有⼀个问题,就是它是存在静态存储区的,即使函数结束栈区收回,这个变量的值也不改变。

static int i=0; 这是⼀条初始化语句⽽不是⼀条赋值语句所以跟i=0不⼀样的。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

关键字Auto:声明自动变量。

在缺省情况下,编译器默认所有变量都是auto的定义和声明:int I;定义就是创建一个对象,为这个对象分配一块内存并给他取一个名字。

一个变量或对象只能定义一次Extern int i声明:告诉编译器,这个名字已经匹配到一块内存上,这个名字已经被预定,别的地方不能再用他当变量名或对象名。

声明可以出现多次Extern可以置于变量或函数前,以表明变量或函数的定义在别的文件中Register:请求编译器尽可能地将变量存在CPU内部寄存器中,而不是通过内存寻址访问注意点,register变量必须是能被CPU寄存器所接受的类型,这就是说register变量必须是单值,并且其长度小于或等于整型的长度。

而且变量不能用取地址符&Static作用:1修饰退出一个块后仍然存在的局部变量2表示不能被其他文件访问的全局变量和函数静态全局变量,作用域仅限于变量被定义的文件中,其他文件及时使用extern声明也没法使用它。

静态局部变量,在函数体里面定义的,就只能在这个函数里使用,同一个文档中的其他函数也用不了。

由于被static修饰的变量总是存在内存的静态区。

当这个函数运行结束,静态变量也不会销毁修饰函数:指对函数的作用域限于本文件,使用静态函数的好处是,不同的人编写不同的函数时,不用担心自己定义的函数是否会有其他文件中的函数同名Bool变量的初始化和if条件句的规范Bool bTestFlag=FALSE;If(bTestFlag); if(!bTestFlag);float变量的初始化和if条件句的规范float fTestVal=0.0;if((fTestVal>=-EPSINON)&&(fTestVal<=EPSINON));指针变量Int *p=NULL;If(NULL==p); if(NULL!=p);Case后面只能是整型或字符型的常量或常量表达式按字母顺序排列各条case语句按执行频率排列case语句Break表示终止本层循环在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的放在最外层,以减少CPU跨切循环层的次数如果函数的参数可以是任意类型指针,那么应声明其参数为void*如内存操作函数void* memcpy(void* dest,const void* src,size_t len)Return语句不能反悔指向栈内存的指针,因为该内存在函数体结束时被自动销毁如char *Func(void){Char str[30];…..Return str;}Const修饰的只读变量先忽略类型名,看const离哪个近就修饰谁Const int *p 修饰*p,*p是指针指向的对象,不可变int * const p 修饰p,p不可变const修饰函数的返回值,返回值不可被改变const int Fun (void)volatile关键字修饰的变量,提醒编译器对访问该变量的代码不再进行优化int i=10;in j=I; //1语句int k=I; //2语句执行上面代码时编译器对代码优化,在1语句时从内存中取出i的值赋给j之后,这个值并没有丢掉,而是在2语句时继续用这个值给k赋值Volatile int i=10;Int j=I;Int k=I;执行上面代码,volatile关键字告诉编译器,i是随时可能发生变化的,每次使用他的时候必须从内存中取出i的值Union中所有的数据成员公用一个空间,所有的数据成员具有相同的起始地址大端模式:字数据的高字节存储在低地址中,低字节存放在高地址中小端模式:字数据的高字节存储在高地址中,低字节存放在低地址中Typedef:给一个已经存在的数据类型(注意:是类型,不是变量)其一个别名Typedef struct student{//code}Stu_st,*Stu_pststruct student *stu1、Stu_pst stu、Stu_st *stu——没有区别表示给struct student{//code}取了个别名叫Stu_st,同时给struct student{//code}*取了个别名叫Stu_pstConst Stu_pst stu2这里Stu_pst是struct student{//code}*的别名。

struct student{//code}*是一个整体。

对于编译器来说Stu_pst是一个类型名,所以在解析的时候会把Stu_pst这个数据类型名忽略掉,所以const修饰的事指针stu2符号双引号引起来的都是字符串常量,单引号引起来的都是字符常量字符常量占1字节字符串常量占2字节逻辑运算符If((++i>0)||(++j>0))语句中,先计算(++i>0),发现其结果为真,后面就不再计算左移右移左移<<:高位丢弃,地位补0右移>>:对于有符号数,符号位将随同移动。

当为正数时最高位补0。

负数时,符号位为1,最高位是补0或补1取决于编译系统规定?++、——作为后缀时在本计算单位结束时自加J=(i++,i++,i++);i在遇到每个逗号后,认为本计算单位已经结束,i这个时候自加k=(i++)+(i++)+(i++);i遇到分号后才认为本计算单位已经结束编译器将程序分解成符号的方法是,从左到有一个一个字符的读入。

每一个符号应该包含尽可能多得字符内存对齐Struct TestStruct1{Char c1;Short s;Char c2;Int I;}查看变量内存地址输出C1 00000000S 00000002C2 00000004I 00000008为了提高程序的性能,数据结构应该尽可能地在自然边界上对齐。

对字、双字和四字来说,自然边界分别是偶数地址、可以被4整除的地址和可以被8整除的地址。

一个字起始地址是奇数但却没有跨越字边界被认为是对齐的Sizeof(TestStruct1)的结果为12避免内存对齐的影响这样设计结构体Struct TestStruct2{Char c1;Char c2;Short s;Int I;}指针指针的大小事一定的,和*前面的数据类型无关,*前面的数据类型只是说明指针所指向的内存里存储的数据类型。

在32位系统下,指针大小都是4字节将数值存储到指定的内存地址Int *p=(int *)0x12ff7c;*p=0x100;或者*(int *)0x12ff7c=0x100;先将地址0x12ff7c强制转换,告诉编译器这个地址上将存储一个int类型的数据。

数组A[0]、a[1]等为a的元素,但并非元素的名字,数组的每一个元素都是没有名字的出现在赋值等号右边的是右值,出现在等号左边的就是左值。

比如x=y左值,编译器认为x的含义是x所代表的地址右值,编译器认为y的含义是y所代表的地址里的内容出现在赋值符左边的符号所代表的地址上的内容一定是可以被修改的A作为右值时其意义与&a[0]是一样的,代表的是数组首元素的首地址,而不是数组的首地址A不能作为左值。

我们只能访问数组的某个元素,而无法把数组当一个总体进行访问A[0]是一个元素,a是整个数组。

&a[0]和&a的值一样,但其意义不一样。

前者是数组首元素的首地址,而后者是数组的首地址A和&a的值是一样的,但意思不一样。

A是数组首元素的首地址,也就是a[0]的首地址,&a是数组的首地址。

A+1是数组下一元素的首地址,即a[1]的首地址。

&a+1是下一个数组的首地址Int main(){Char a[5]={‘a’,’b’,’c’};Char (*p3)[4]=&a;Char (*p4)[4]=a;}P3这个定义等号两边的数据类型完全一致,而p4这个定义等号左边的类型是指向整个数组的指针,右边的数据类型是指向单个字符的指针当一维数组作为函数参数的时候,编译器总是把它解析成一个指向其首元素首地址的指针2用二级指针*(&str)就是str。

所以malloc分配的内存地址是真正赋给了str本身Void fun(char *p[4])可以写成void fun(char **p)因为参数*p[4],对于p来说,它是一个包含4个指针的一维数组,同样把这个一维数组也改写为指针的形式,那就得到上面的写法Char * (*fun)(char * p1,char * p2)这里fun不是函数名,而是一个指针变量,它指向一个函数。

这个函数的返回值是一个指针堆、栈和静态区堆:由malloc系列函数或new分配内存,其生命周期由free或delete决定。

在没有释放之前一直存在,直到程序结束。

堆上的内存会产生内存泄露栈:保存局部变量。

栈上的内容只在函数的范围内存在,当函数运行结束,这些内容也会自动被销毁静态区:保存自动全局变量和static变量(包括static全局和局部变量)。

静态区的内容在整个程序的生命周期内都存在,由编译器在编译的时候分配Assert是一个宏而不是函数,包含在assert.h头文件中只有字符串常量才有结束标识符\0。

比如下面这种写法就没有结束标识符Char a[3]={‘a’,’b’,’c’}Free的作用,斩断指针变量与这块内存的关系,但是指针变量p本身保存的地址并没有改变,但它对这个地址处的那块内存已经没有所有权了使用free函数之后需要重新吧p的值变为NULL。

相关文档
最新文档