C语言之精华总结
- 格式:doc
- 大小:135.00 KB
- 文档页数:96
C语言知识点总结(完美版)C语言最重要的知识点总体上必须清楚的:1)程序结构是三种: 顺序结构、选择结构(分支结构)、循环结构。
2)读程序都要从main()入口, 然后从最上面顺序往下读(碰到循环做循环,碰到选择做选择),有且只有一个main函数。
3)计算机的数据在电脑中保存是以二进制的形式. 数据存放的位置就是他的地址.4)bit是位是指为0 或者1。
byte 是指字节, 一个字节 = 八个位.概念常考到的:1、编译预处理不是C语言的一部分,不占运行时间,不要加分号。
C语言编译的程序称为源程序,它以ASCII数值存放在文本文件中。
2、#define PI 3.1415926; 这个写法是错误的,一定不能出现分号。
3、每个C语言程序中main函数是有且只有一个。
4、在函数中不可以再定义函数。
5、算法:可以没有输入,但是一定要有输出。
6、break可用于循环结构和switch语句。
7、逗号运算符的级别最低,赋值的级别倒数第二。
第一章 C语言的基础知识第一节、对C语言的基础认识1、C语言编写的程序称为源程序,又称为编译单位。
2、C语言书写格式是自由的,每行可以写多个语句,可以写多行。
3、一个C语言程序有且只有一个main函数,是程序运行的起点。
第二节、熟悉vc++1、VC是软件,用来运行写的C语言程序。
2、每个C语言程序写完后,都是先编译,后链接,最后运行。
(.c—.obj—.exe)这个过程中注意.c和.obj文件时无法运行的,只有.exe文件才可以运行。
(常考!)第三节、标识符1、标识符(必考内容):合法的要求是由字母,数字,下划线组成。
有其它元素就错了。
并且第一个必须为字母或则是下划线。
第一个为数字就错了2、标识符分为关键字、预定义标识符、用户标识符。
关键字:不可以作为用户标识符号。
main define scanf printf 都不是关键字。
迷惑你的地方If是可以做为用户标识符。
因为If中的第一个字母大写了,所以不是关键字。
C语言的知识点和难点总结C语言是一种基础编程语言,广泛应用于系统软件、嵌入式系统、游戏开发等领域。
在学习C语言的过程中,我们会遇到一些知识点和难点。
下面,我们将对C语言的知识点和难点进行总结。
一、知识点:1.数据类型:C语言支持多种数据类型,包括整型、浮点型、字符型等。
这些数据类型的使用是C语言编程的基础,需要熟练掌握。
2.运算符:C语言提供了丰富的运算符,如算术运算符、关系运算符、逻辑运算符等。
理解并正确使用这些运算符是编写高效代码的关键。
3.控制结构:C语言中的控制结构包括条件语句(如if-else)、循环语句(如for、while)等。
掌握这些控制结构是实现程序逻辑的关键。
4.函数:函数是C语言的基本模块,用于实现特定的功能。
了解如何定义函数、调用函数以及传递参数是十分重要的。
5.指针:指针是C语言的特色之一,它允许我们直接访问内存地址。
理解指针的概念和用法对于深入学习C语言至关重要。
6.结构体与联合:结构体和联合是C语言中处理复杂数据结构的重要工具。
通过它们,我们可以组合不同类型的数据并进行操作。
二、难点:1.指针操作:由于指针直接涉及内存地址,因此对初学者来说可能较难理解。
掌握指针的基本概念、声明、初始化和使用是C语言学习的难点之一。
2.内存管理:在C语言中,程序员需要直接管理内存。
如何正确地分配和释放内存是避免内存泄漏和段错误的关键,也是学习C语言的难点。
3.深度递归:深度递归可能导致栈溢出或性能问题,因此在实际应用中需要谨慎处理。
理解递归原理并在合适的场景下应用是C语言学习的一个难点。
4.多线程编程:多线程编程涉及线程的创建、同步和通信等复杂概念,对于初学者来说可能较难掌握。
理解多线程的原理和应用是多线程编程的难点之一。
C知识点(徐向前整理)数据类型:整型:基本整型—int--%d长整型---long--%ld短整型—short--%d实型:单精度—float--%f双精度—double--%lf长双精度--long double字符型:--char--%c[‘A’表示字符A]【char cha; cha=’A’(只能这样)】变量定义:单个变量:int a;(关键词加变量名,以分号结尾)多个变量:int a,b,c;(关键词加变量名1,变量名2,…)运算符:算术运算符+ - * /(除) %(取余)关系运算符> >= < <= !=(不等于) ==(等于)逻辑运算符!(非) &&(且) ||(或)赋值运算符= += *= /= -=Eg: s+=i等于s=s+I S*=i等于s=s*i优先级别算数>关系>逻辑>赋值特别注意:(1)除法运算:除法的运算结果和运算对象的数据类型有关【整数整数=整数、浮点数整数=整数浮点数=浮点数】(2)取余运算:商与被除数符号相同(同正或者同负)(3)C语言对在真假的处理:非0是真,0是假;真用1,假用0;&&左边表达式为假,则右边不执行;||左边表达式为真,则右边不执行,左边为假,则执行右边;数据的输入与输出:printf作用:将变量的内容输入到显示器上。
用法:1.printf (“字符串\n”);2. printf (“输出控制符\n”,输出参数);eg: printf (“%d\n”,a);3. printf (“输出控制符1\n输出控制符2\n…输出控制符m\n”,输出参数1, 输出参数2,…输出参数m,);【输出控制符与输出参数一一对应】eg: printf (“%d\n%d\n%d\n”,a,b,c);4. printf (“输出控制符非输出控制符”,输出参数);Scanf作用:通过键盘将数据输入到变量中用法:1.scanf(“输入控制符”,输入参数);功能:将从键盘中输入的字符转化为输入控制符所规定格式的数据,然后存入以输入参数的值为地址的变量中。
C语言小结一、C语言结构1、主函数用main作为函数名,每个C程序都必须包含且仅含一个main函数,C程序的执行是从主函数中的第一句开始,到主函数中的最后依据结束2、头文件的引用#include<name.h>或#include“name.h”3、函数由函数首部和函数体组成:函数首部,即函数的第一行,包括函数名、函数类型、函数参数名和参数类型,一个函数后面必须跟一对圆括号;函数体,及函数首部下面的花括号{}内的部分,如果一个函数内有多个花括号,最外层的一对{}为函数体的范围二、数据类型及其运算1、标识符:标识符可作变量名、符号名、函数名、数组名、文件名以及具有特定含义的名字。
合法的标识符由字母、数字和下划线组成,并且第一个字符必须为字母或下划线,C语言区分字母大小写2、数据类型分类:整型: int,长整型以long int或long表示;实型:单精度float、双精度double、长双精度型long double; 字符型:char 结构体:用户定义的一种数据结构,它包含若干个不同数据类型(当然也可以相同)的数据项,这些数据之间有内在的联系共用体:使几个不同的变量共占同一段内存的结构指针类型:专门用来存放地址的数据类型空类型:在定义的时候不确定数据类型,而在使用的时候通过强制转换来确定的数据类型定义:结构体如:struct student {int num;char name[20];}student1,student2; 共用体:union 共用体名{成员表列}变量表列;空类型:基本型*指针变量名如float *p;3、C运算符的种类、运算优先级和结合性见课本365面(很重要)4、数据转换:自动转化(内存长度低的向高转)强制转换:将结果转换成所需要的数据类型,如;float s=1.23; int a; a=(int)s;5、C表达式类型和求值规则:赋值表达式:<变量><赋值运算符><表达式> 算术表达式关系表达式:一般表达式:<表达式1><关系运算符><表达式2>(“真”用1表示“假”用0表示)逻辑表达式:一般形式<表示式1><逻辑运算符><表达式2>(真1、假0)条件表达式:一般形式:表达式1?表达式2:表达式3 逗号表达式:一般形式:表达式1,表达式2,……,表达式n。
大学c语言知识点总结学习一门课程要有耐心,要肯下功夫,上课就要留意简单的出路图片,C语言只是一个工具而已,它也要靠人来操作,下面是XXXX为大家整理的关于大学c语言知识点总结,希望对您有所帮助。
欢迎大家阅读参考学习!大学c语言知识点总结1为期一个星期的c++实训已经基本结束,但是给了我很大的影响。
通过这次实训,使我明白C++语言这门课程光仅仅是听课是远远不够的,上机训练也不容忽视。
通过上机训练,才能够明白自己知识的不足,才能够有的放矢,更加深刻的理解C语言中的知识点。
通过实训,我找到了许多知识漏点,学到了很多以前不懂的知识,以前认为自己已经懂了的知识点也理解更加深刻了。
尤其是遇到了自己当时不知道如何编写的C++语言题目如何编写,通过自己的学习和同同学的交流后,试编和改错,最后能够顺利的编写出来,带来的也有成就感。
并增加了我们对C++语言的兴趣和学好C++语言的信心。
与同学们交流的过程中,了解了程序的多种解决方法,知道了不同编写方法有不同的特点。
总结C++语言实训的几个重要作用:1.加深对课堂讲授内容的理解课堂上要讲授许多关于C++语言的语法规则,听起来十分枯燥无味,也不容易记住,死记硬背是不可取的。
然而要使用C++语言这个工具解决实际问题,又必须掌握它。
通过多次上机练习,对于语法知识有了感性的认识,加深对它的理解,在理解的基础上就会自然而然地掌握C++语言的语法规定。
对于一些内容自己认为在课堂上听懂了,但上机实践中会发现原来理解的偏差。
学习C++语言不能停留在学习它的语法规则,而是利用学到的知识编写C++语言程序,解决实际问题。
即把C++语言作为工具,描述解决实际问题的步骤,由计算机帮助我们解题。
只有通过上机才能检验自己是否掌握C++语言、自己编写的程序是否能够正确地解题。
自己编好程序上机调试运行时,可能有很多你想不到的情况发生,通过解决这些问题,可以逐步提高自己对C++语言的理解和程序开发能力。
c语言心得总结(五篇)1、学C语言,让我能够更加深入199地认识程序设计思维,研究计算机科学知识的规律,了解计算机识别和运行的思路,有利于我以后更好的开发能力提高。
学习C语言,让我更加深刻地了解计算机编程的奥秘,即如何在计算机上对数据进行存储、修改、处理和分析的过程,使得程序具有更强的运行效率,编写更高质量的代码。
学习C语言同时,让我认识到在编写程序时,要设计和搭建复杂的数据结构,首先要用简单、清晰的程序语句,明确程序的层次和逻辑结构,使程序不会出现不必要的复杂性;同时,还要学会利用函数、结构体和链表等特点,正确地使用数据类型和变量,完成复杂的程序结构和流程,才能避免出现意外的结果。
C语言的学习也让我更加熟悉计算机底层操作系统,让我了解各种不同的跨平台库函数,以及计算机编程与数据结构、汇编程序等概念之间的关系,有助于我熟练掌握计算机语言,为后期自己的开发打下良好的基础。
2、学习C语言可以说是程序员的基础必备知识,其核心理念和结构可以帮助我们理解和掌握其它更高级的编程语言。
它的语法和抽象表示形式都很简单,使得我们可以更好的掌握编程思想,并且与其他编程语言的关联程度很高,有助于我们把学到的一些基础知识与工作中遇到的重要技术建立联系。
C语言可以说是计算机科学领域最流行的编程语言之一,它可以帮助我们实现高性能、安全、稳定的软件开发,是程序员最常使用的编程语言之一。
学习它能有助于我们更加熟练地使用计算机语言编程,从而更好的掌握计算机科学,在后期的学习和工作中有更强的能力。
3、学习一门语言一定要从简单的开始,学习C语言,让我深入的了解了计算机的基本工作原理,从而了解程序设计的基本思想和方法,这是我在学习C语言的过程中最大的收获。
C语言是一种结构化的编程语言,其特点是可移植性强、能够通过简单的修改就可以实现针对不同平台的编译,有助于节省成本并降低软件开发过程中出现的问题。
在使用C语言编写程序时首先要搞清楚语法,然后要理解基本的控制结构:条件判断,循环等等,这些都是程序设计的基本知识,让我能够将这些知识都应用到C编程语言中,有助于提高程序设计的能力。
c语言重点知识点总结c语言重点知识点总结上学的时候,说起知识点,应该没有人不熟悉吧?知识点是指某个模块知识的重点、核心内容、关键部分。
还在苦恼没有知识点总结吗?下面是小编帮大家整理的c语言重点知识点总结,欢迎大家分享。
c语言重点知识点总结篇1◆知识点1:交换两个变量值的方法1)采用第三方变量(最容易想到的方法)2)采用加减法进行值得交换(面试时常用**)代码如下:b = a - b;a = a - b;b = a + b;3)采用按位异或的位方式代码如下:a = a^b;b = a^b;a = a^b;◆知识点2:取语言重点知识点总结余运算%的结果与被除的符号相同,结果为两个正数取余后前面加符号◆知识点3:sizeof的使用sizeof是一种运算符不要想当然理解为函数sizeof使用时可以不加()sizeof可以加变量、常量、数据类型跟数据类型是必须加()◆知识点4:static和 extern区别是能否进行跨文件访问①函数②变量1、对函数的作用:外部函数:定义的函数能被本文件和其他文件访问内部函数:定义的函数只能被本文件访问默认情况下,所有函数都是外部函数(相当于带关键字extern),所以可以省略extern作用:完整的定义和引用一个外部函数都加extern引用时也是默认是外部函数所以也省略externstatic作用:定义一个内部函数使用:static返回类型函数名(参数列表)不能被其他文件调用一个项目中,本文件的外部函数名不能和其他文件的外部函数同名(error)本文件中的内部函数(static)可以和其他文件的函数名同名的2、对变量的作用:全局变量分为两种:外部变量:定义的变量可以被其他文件访问①默认情况下所有的全局变量都是外部变量②不同文件中的同名外部变量都代表同一个③定义一个外部变量不加extern,声明才加extern同样的声明是没有错误的内部变量:定义的变量不能被其他文件访问不同文件的同名内部变量互不影响◆知识点5:数组的几种初始化方式如下:int a[3] = {10, 9, 6};int a[3] = {10,9};int a[] = {11, 7, 6};int a[4] = {[1]=11,[0] = 7};(知道有此种初始化方式即可)◆知识点6:数组的内存分析和注意点存储空间的划分(内存的分配是从高地址到低地址进行的,但一个数组内部元素又是从低到高进行的)【注:对于以后学习重要】数组名的作用,查看元素地址注意数组不要越界◆知识点7:字符串知识点"123”其实是由’1’、’2’、’3’、’’组成字符串的输出”%s”,’’是不会输出的◆知识点8 :字符串处理函数:strlen()计算的是字符数,不是字数计算的字符不包括’’,一个汉字相当于3个字符例子:"哈haha" 字符数为7从某个地址开始的数字符个数,知道遇到’’为止指针部分在C语言中占据重要地位,所以重点学习与整理了指针的知识:◆知识点9:指针定义的格式变量类型 *变量名如:Int *p◆知识点10:指针作用能够根据一个地址值,访问对应的.存储空间例:Int *p;Int a = 90;P = &a;*p = 10;//把10赋值给p所指的存储空间◆知识点11:指针使用注意Int *p只能指向int类型的数据指针变量只能存储地址指针变量未经初始化不要拿来间接访问其他存储空间◆知识点12:指针与数组遍历数组int ages[5] = {10, 4, 9, 44, 99};for(int i = 0; i<5; i++){printf("%d ", ages[i]);}使用指针遍历数组:int *p;// 指针变量P指向了数组的首地址p = &ages[0];// 使用指针遍历数组for(int i = 0; i<5; I++){printf("ages[%d] = %d ", i, *(p + i));}注:指针+ 1取决于指针的类型注:数组的访问方式数组名[下标]指针变量名[下标]*(p + i)◆知识点12:指针与字符串定义字符串的两种方式:1、利用数组Char name[] = “Andyzhao”特点:字符串里的字符可以修改适用场合:字符串内容需要经常修改2、利用指针Char *name = “itcast”特点:字符串是一个常量,字符串里面的字符不能修改使用场合:字符串的内容不需要修改,而这个字符串经常使用◆知识点13:预处理指令(三种):宏定义条件编译文件包含1、宏定义的配对使用和带参数的宏:#define#undef带参数的宏:#define sum(v1,v2) ((v1) + (v2))//括号是必须的例如:#define pingfang(a) a*a#define pingfang(a) (a*a)调用时pingfang(10)/pingfang(2)//不正确pingfang(5+5)//不正确带参数的宏效率比函数高2、条件编译(一般是判断宏的值)#if 条件#elif 条件#else#endif(非常重要)不然后面的代码全部无效3、文件包含:<>表示系统自带的文件,""表示自定义文件不允许循环包含,比如ah包含bh,bh又包含ah◆知识点14:typedef 只是给类型起了个别名并不是定义新类型struct Student{int age;char *name;};typedef struct Student Student;等价于typedef struct Student{int age;char *name;}Student;也等价于typedef struct {int age;char *name;}Student;类似的给枚举类型起名typedef enum Sex{Man,Women}Sex;下面这种情况的写法比较特殊//下面是函数指针类型的自定义数据类型,返回值类型和参数类型要匹配#includetypedef int (*TypeFuncPointer)(int, int);int add(int a, intb){return a + b;}int minus(int a, intb){return a - b;}int main(){TypeFuncPointer p = add;//使用自定义类型TypeFuncPointer p2 = minus;//使用自定义类型printf("add = %d ",p(1, 2));printf("minus = %d ",p2(1, 2)); return 0;}下面是定义结构体的指针类型typedef struct Student{int age;char *name;}*PtrStu;//使用方式Student stu ={18, "zhangsan"}; PtrStu p = &stu;宏定义也是可以为类型起名的#define Integer int相当于typedef int Integer注意和typedef的区别例如:typedef char * String#define String2char *。
c语言全部知识点总结一、基本语法1.1 数据类型C语言的数据类型包括基本数据类型和派生数据类型。
基本数据类型包括整型、浮点型、字符型和布尔型。
派生数据类型包括指针、数组、结构体和联合体。
1.2 变量在C语言中,变量用于存储数据。
变量需要声明后才能使用,并且需要指定变量的数据类型。
1.3 运算符C语言支持多种运算符,包括算术运算符、关系运算符、逻辑运算符和位运算符等。
1.4 控制语句C语言支持多种控制语句,包括条件语句、循环语句和跳转语句。
1.5 函数C语言是一种函数式语言,函数是C程序的基本构建块。
函数包括函数声明、函数定义和函数调用。
1.6 数组数组是一种派生数据类型,用于存储多个相同类型的数据。
数组可以是一维数组、多维数组或字符数组。
1.7 指针指针是一种派生数据类型,用于存储变量的地址。
指针的主要作用是进行动态内存分配和实现数据结构。
1.8 结构体和联合体结构体和联合体是C语言提供的两种复合数据类型,用于存储多个不同类型的数据。
1.9 文件操作C语言提供了一组函数,用于进行文件操作,包括打开文件、关闭文件、读写文件等。
1.10 宏定义宏定义是C语言中的一种预处理指令,用于在程序中定义常量、函数和条件编译等。
二、高级特性2.1 动态内存分配C语言通过malloc()和free()等函数实现动态内存分配,从而支持对内存的灵活管理。
2.2 递归C语言支持递归函数,允许函数调用自身。
递归通常用于解决分而治之的问题。
2.3 指针运算C语言支持指针运算,包括指针加法、指针减法和指针比较等。
指针运算通常用于实现数据结构和算法。
2.4 多线程编程C语言通过pthread库支持多线程编程,允许程序在多个线程中并发执行。
2.5 动态链接库C语言支持动态链接库,允许程序在运行时加载共享库,并调用共享库中的函数。
2.6 面向对象编程C语言可以通过结构体和函数指针实现面向对象编程,在一定程度上模拟类和对象的概念。
2.7 编译预处理C语言提供了一组预处理指令,允许程序在编译前进行文本替换、条件编译和包含文件等操作。
C语⾔基础知识总结⼤全1.⼊门程序#include <stdio.h>int main(){printf("Hello World!");return 0;}2.数据类型数据类型:1.基本数据类型:1.1. 整型:int 4个字节1.2. 字符型:char 1个字节1.3. 实型(浮点型)1.3.1.单精度型:float 4个字节1.3.2.双精度型:double 8个字节2.构造类型:2.1.枚举类型2.2.数组类型2.3.结构体类型2.4.共⽤体类型3.指针类型:4.空类型:3.格式化输出语句%d:⼗进制整数;%c:单个字符;%s:字符串;%f:6位⼩数;#include <stdio.h>int main(){int age = 18;float height = 1.85;char unit = 'm';printf("⼩明今年%d岁\n", age);printf("⼩明⾝⾼%f%c\n", height, unit);printf("⼩明现在在慕课⽹上学习IT技术\n");return 0;}4.常量值不发⽣改变的量成为常量;定义字符常量(注意后⾯没有;)#include <stdio.h>#define POCKETMONEY 10 //定义常量及常量值int main(){printf("⼩明今天⼜得到%d元零花钱\n", POCKETMONEY);return 0;}5.1.算数运算符:+,-,*,/,%,++,--;前++/--,先运算,再取值.后++/--,先取值,再运算;5.2.赋值运算符:5.3.关系运算符;5.4.逻辑运算符;5.5.三⽬运算符:表达式1 ? 表达式2 : 表达式3;6.⽔仙花数计算输出所有三位数的⽔仙花数字所谓“⽔仙花数”是指⼀个三位数,其各位数字⽴⽅和等于该数,如:153就是⼀个⽔仙花数,153=111+555+333。
C语言是当代人学习及生活中的必备基础知识,应用十分广泛,下面为大家带来C语言基础知识梳理总结,C语言零基础入门绝对不是天方夜谭!算法结构:一、顺序结构、选择结构、循环结构;二、循环结构又分为while型、until型、for循环结构;程序流程图;结构化程序设计方法:(1)自顶向下;(2)逐步细化;(3)模块化设计;(4)结构化编码。
数据类型:常量:常量包括字面常量、直接常量和符号常量;变量:C语言规定标志符只能由字母、数字和下划线三种字符组成,且第一个字符必须是字母或者下划线;必须压迫先定义后使用;每一个变量被定义以确定类型后,在编译时就能为其分配相应的存储单元;整数类型:整数常量有十进制、八进制和十六进制;“%d”整形变量:数据在内存中存放形式是以二进制形式存放;有int型、short int型和long int 型,无符号整型变量的范围是-32768—32767,有符号型为0~65535.通常把long定义为32位,把short定义为16位,int可以是32位也可以为16位,这都主要取决于机器字长。
实型常量的表示方法:(1)十进制,0.0;(2)指数形式,123e3实型变量:实数型数据在内存中的存放形式,一般在内存中占4个字节,分成整数部分和小数部分存放。
实型变量分为float型、double型long double型。
实型数据会存在舍入误差。
实型常量的类型:C编译系统将实型常量作为双精度来处理。
字符型数组:(一)字符常量:转义字符(\n——换行,\t——tab,\r——回车,\f——换页,\b——退格,\ddd——1到3位8进制的数代表的字符)(二)字符变量:字符数据存储形式实际是以ASCII码存储。
“%c”字符串常量:双撇号括起来的一系列字符序列。
C的运算符有以下几种:1、算术运算符(+ - * / %)结合方向自左向右2、关系运算符(> <=="">=<=!="">3、逻辑运算符(! && ||)4、位运算符(<>> ~ | ^ &)5、赋值运算符(=及符号扩展赋值运算符)6、条件运算符(? : )7、逗号运算符( , )8、指针运算符(* &)9、求字节运算符(sizeof)10、强制类型转换运算符((类型))11、分量运算符( . ->)12、下标运算符([])13、其他控制语句:完成一定的控制功能。
从研究生二年纪开始学习计算机也差不多两年了,一路走来,有很多的收获,也有不少的遗憾,现在正好有一段闲暇,就想对走过的路留下一些足迹,回忆。
每个人都有自己不同的人生,说到这里,就是程序人生了,歌德在《浮士德》中说过:―如果不曾在悲哀中咀嚼过面包,不曾在哭泣中等待过明天,这样的人就不知道你——天的力量。
‖所以我想记下一些带给我悲哀,带给我哭泣的程序人生。
其实学习计算机的基础课程是非常重要的,离散数学,编译原理,操作系统,形式语言……,如果你认真走过了这些路,在以后的日子你会发现你的路会越走越宽,以前的努力和汗水会不断的给你灵感,给你支持,给你前进的武器和勇气。
你会发现以后取得的很多成就,不过是朝花夕拾而已!对于程序语言我喜欢的是C++,它能带给你别的语言无法给予你的无上的智力快感,当然也会给你一门语言所能给你的魔鬼般的折磨。
其实Java,C#,Python 语言也非常的不错,我也极为喜欢。
它们都是非常成功的语言,我从来就不愿意做某一种语言的盲目信仰者,每种语言都有它成功的地方,失败的地方,都有它适合的地方,不如意的地方。
所以每一次看到评价语言的文章,我看看,但从来不会发言。
C++的前世是C,而且C所留下的神秘以及精简在C++中是青出于蓝而胜于蓝!C所带给人的困惑以及灵活太多,即使一个有几年经验的高段C程序员仍然有可能在C语言的小水沟里翻船。
不过其实C语言真的不难,下面我想指出C语言中最神秘而又诡谲多变的四个地方,它们也继续在C++语言中变幻莫测。
指针,数组,类型的识别,参数可变的函数。
一.指针。
它的本质是地址的类型。
在许多语言中根本就没有这个概念。
但是它却正是C灵活,高效,在面向过程的时代所向披靡的原因所在。
因为C的内存模型基本上对应了现在von Neumann(冯·诺伊曼)计算机的机器模型,很好的达到了对机器的映射。
不过有些人似乎永远也不能理解指针【注1】。
注1:Joel Spolsky就是这样认为的,他认为对指针的理解是一种aptitude,不是通过训练就可以达到的.joelonsoftware./pr ... /fog0000000073.html指针可以指向值、数组、函数,当然它也可以作为值使用。
看下面的几个例子:int* p;//p是一个指针,指向一个整数int** p;//p是一个指针,它指向第二个指针,然后指向一个整数int (*pa)[3];//pa是一个指针,指向一个拥有3个整数的数组int (*pf)();//pf是一个指向函数的指针,这个函数返回一个整数后面第四节我会详细讲解标识符(identifier)类型的识别。
1.指针本身的类型是什么?先看下面的例子:int a;//a的类型是什么?对,把a去掉就可以了。
因此上面的4个声明语句中的指针本身的类型为:int*int**int (*)[3]int (*)()它们都是复合类型,也就是类型与类型结合而成的类型。
意义分别如下:point to int(指向一个整数的指针)pointer to pointer to int(指向一个指向整数的指针的指针)pointer to array of 3 ints(指向一个拥有三个整数的数组的指针)pointer to function of parameter is void and return value is int (指向一个函数的指针,这个函数参数为空,返回值为整数)2.指针所指物的类型是什么?很简单,指针本身的类型去掉―*‖号就可以了,分别如下:intint*int ()[3]int ()()3和4有点怪,不是吗?请擦亮你的眼睛,在那个用来把―*‖号包住的―()‖是多余的,所以:int ()[3]就是int [3](一个拥有三个整数的数组)int ()()就是int ()(一个函数,参数为空,返回值为整数)【注2】注2:一个小小的提醒,第二个―()‖是一个运算符,名字叫函数调用运算符(function calloperator)。
3.指针的算术运算。
请再次记住:指针不是一个简单的类型,它是一个和指针所指物的类型复合的类型。
因此,它的算术运算与之(指针所指物的类型)密切相关。
int a[8];int* p = a;int* q = p + 3;p++;指针的加减并不是指针本身的二进制表示加减,要记住,指针是一个元素的地址,它每加一次,就指向下一个元素。
所以:int* q = p + 3;//q指向从p开始的第三个整数。
p++;//p指向下一个整数。
double* pd;……//某些计算之后double* pother = pd – 2;//pother指向从pd 倒数第二个double数。
4.指针本身的大小。
在一个现代典型的32位机器上【注3】,机器的内存模型大概是这样的,想象一下,内存空间就像一个连续的房间群。
每一个房间的大小是一个字节(一般是二进制8位)。
有些东西大小是一个字节(比如char),一个房间就把它给安臵了;但有些东西大小是几个字节(比如double就是8个字节,int就是4个字节,我说的是典型的32位),所以它就需要几个房间才能安臵。
注3:什么叫32位?就是机器CPU一次处理的数据宽度是32位,机器的寄存器容量是32位,机器的数据,内存地址总线是32位。
当然还有一些细节,但大致就是这样。
16位,64位,128位可以以此类推。
这些房间都应该有编号(也就是地址),32位的机器内存地址空间当然也是32位,所以房间的每一个编号都用32位的二进制数来编码【注4】。
请记住指针也可以作为值使用,作为值的时候,它也必须被安臵在房间中(存储在内存中),那么指向一个值的指针需要一个地址大小来存储,即32位,4个字节,4个房间来存储。
注4:在我们平常用到的32位机器上,绝少有将32位真实内存地址空间全用完的(232 =4G),即使是服务器也不例外。
现代的操作系统一般会实现32位的虚拟地址空间,这样可以方便运用程序的编制。
关于虚拟地址(线性地址)和真实地址的区别以及实现,可以参考《Linux 源代码情景分析》的第二章存储管理,在互联网上关于这个主题的文章汗牛充栋,你也可以google一下。
但请注意,在C++中指向对象成员的指针(pointer to member data or member function)的大小不一定是4个字节。
为此我专门编制了一些程序,发现在我的两个编译器(VC7.1.3088和Dev-C++4.9.7.0)上,指向对象成员的指针的大小没有定值,但都是4的倍数。
不同的编译器还有不同的值。
对于一般的普通类(class),指向对象成员的指针大小一般为4,但在引入多重虚拟继承以及虚拟函数的时候,指向对象成员的指针会增大,不论是指向成员数据,还是成员函数。
【注5】。
注5:在Andrei Alexandrescu的《Modern C++ Design》的5.13节Page124中提到,成员函数指针实际上是带标记的(tagged)unions,它们可以对付多重虚拟继承以及虚拟函数,书上说成员函数指针大小是16,但我的实践告诉我这个结果不对,而且具体编译器实现也不同。
一直很想看看GCC的源代码,但由于旁骛太多,而且心不静,本身难度也比较高(这个倒是不害怕^_^),只有留待以后了。
还有一点,对一个类的static member来说,指向它的指针只是普通的函数指针,不是pointer to class member,所以它的大小是4。
5.指针运算符&和*它们是一对相反的操作,&取得一个东西的地址(也就是指针),*得到一个地址里放的东西。
这个东西可以是值(对象)、函数、数组、类成员(class member)。
其实很简单,房间里面居住着一个人,&操作只能针对人,取得房间号码;*操作只能针对房间,取得房间里的人。
参照指针本身的类型以及指针所指物的类型很好理解。
小结:其实你只要真正理解了1,2,就相当于掌握了指针的牛鼻子。
后面的就不难了,指针的各种变化和C语言中其它普通类型的变化都差不多(比如各种转型)。
二.数组。
在C语言中,对于数组你只需要理解三件事。
1.C语言中有且只有一维数组。
所谓的n维数组只是一个称呼,一种方便的记法,都是使用一维数组来仿真的。
C语言中数组的元素可以是任何类型的东西,特别的是数组作为元素也可以。
所以inta[3][4][5]就应该这样理解:a是一个拥有3个元素的数组,其中每个元素是一个拥有4个元素的数组,进一步其中每个元素是拥有5个整数元素的数组。
是不是很简单!数组a的内存模型你应该很容易就想出来了,不是吗?:)2.数组的元素个数,必须作为整数常量在编译阶段就求出来。
int i;int a;//不合法,编译不会通过。
也许有人会奇怪char str[] = ―test‖;没有指定元素个数为什么也能通过,因为编译器可以根据后面的初始化字符串在编译阶段求出来,不信你试试这个:int a[];编译器无法推断,所以会判错说―array size missing in a‖之类的信息。
不过在最新的C99标准中实现了变长数组【注6】注6:如果你是一个好奇心很强烈的人,就像我一样,那么可以查看C99标准6.7.5.2。
3.对于数组,可以获得数组第一个(即下标为0)元素的地址(也就是指针),从数组名获得。
比如int a[5]; int* p = a;这里p就得到了数组元素a[0]的地址。
其余对于数组的各种操作,其实都是对于指针的相应操作。
比如a[3]其实就是*(a+3)的简单写法,由于*(a+3)==*(3+a),所以在某些程序的代码中你会看到类似3[a]的这种奇怪表达式,现在你知道了,它就是a[3]的别名。
还有一种奇怪的表达式类似a[-1],现在你也明白了,它就是*(a-1)【注7】。
注7:你肯定是一个很负责任的人,而且也知道自己到底在干什么。
你难道不是吗?:)所以你一定也知道,做一件事是要付出成本的,当然也应该获得多于成本的回报。
我很喜欢经济学,经济学的一个基础就是做什么事情都是要花成本的,即使你什么事情也不做。
时间成本,金钱成本,机会成本,健康成本……可以这样说,经济学的根本目的就是用最小的成本获得最大的回报。
所以我们在自己的程序中最好避免这种邪恶的写法,不要让自己一时的智力过剩带来以后自己和他人长时间的痛苦。
用韦小宝的一句话来说:―赔本的生意老子是不干的!‖但是对邪恶的了解是非常必要的,这样当我们真正遇到邪恶的时候,可以免受它对心灵的困扰!对于指向同一个数组不同元素的指针,它们可以做减法,比如int* p = q+i;p-q的结果就是这两个指针之间的元素个数。
i可以是负数。
但是请记住:对指向不同的数组元素的指针,这样的做法是无用而且邪恶的!对于所谓的n维数组,比如int a[2][3];你可以得到数组第一个元素的地址a和它的大小。