c语言的几个重要知识点_第1页
c语言的几个重要知识点_第2页
c语言的几个重要知识点_第3页
c语言的几个重要知识点_第4页
c语言的几个重要知识点_第5页
免费预览已结束,剩余32页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

c语言的几个重要学问点名目:1.内存构造2指针字符串处理裢表复习大纲中的一些学问点理解1这是核心中的核心,请认真看完,充分理解,否则请不要看下一节内容。4GB的内存,这个内存叫虚拟内存,是概念上的,真正能用到的,只是很小一局部,一般也就是在几百K到几百M。我们PC中内存,我们称之为物256M,512M们不需要管它。我们只需要管好我们自己程序的那4GB内存就可以了。点请留意,系统并不让我们全部都可以用。其中后面2GB的内容是留给系统用的,用户是2GB0x00000000就不能访问。具体是哪些区段,不必关心。要治理4GB点请留意,系统并不让我们全部都可以用。其中后面2GB的内容是留给系统用的,用户是2GB0x00000000就不能访问。具体是哪些区段,不必关心。0x1234567812345678H1030541989616进制表示法,16进制是为了便利显示及计算机计算。程序都是用来做一些具体的事情,不管做什么事,构造都是很相像。程序启动,就有4GBCPU的计算,转变内存的内容,最终再复制内存的内容输出,输出的目的地可以是:屏幕、文件、磁盘等外存、端口、网络等。如何输出呢,最终全部都是调用系统API,由操作系统完成。(这段话,请认真体会,并牢牢记住)所以我们的核心问题就是:如何把握内存,让内存里的值,变成我们想要的结果。留意:这里的把握,指读取或写入某段内存的内容。在虚拟内存4个区域:栈(stack)堆(heap)静态区域(static)数据区域(data)留意:不同的资料可能到具体的分法,有所不同,但大体上就是这样,我也是这样理解的。如以以下图:有兴趣的话,可以参考《Windows核心编程》第三版,里面有具体的论述。栈:intx;charc;chars[10];整个程序中,栈的区域是一个连续的区域,其大小在VC6.01M。这个栈的特点有序:#include<stdio.h>voidExecuteOtherCode{/*...*/}voidTestStack1{inta=1;intb=2;ExecuteOtherCode;}voidTestStack2{intc=3;intd=4;ExecuteOtherCode;}voidmain{TestStack1;TestStack2;}VC6中是从高地址到低地址。TestStack1,其中定义一个变量a,此时a就是在栈中安排一段大小为sizeof(int)a的地址&a0x0012ff28aint4B(其具体介绍参见稍后的留意)b0x0012ff24,这两个内存的安排过程我们称之为“入栈”。见以以下图:TestStack1完毕后,系统则先收回b的空间,再收加a空间,这个过程我们叫“出栈”。即0x0012ff28到0x0012ff28-2*4这段空间的内容不再有用了,即使其值还没有变化。接TestStack2intc,d,同样进展入栈操作,这样c,d很“可能”a,b的空间,见以以下图:任何类型的指针均为任何类型的指针均为4B4G的虚拟内存,2324G。这里用到这里用到“可能”放在栈中,这样就会造成两个类似函数中的变量所占据的内存空间不一样。sizeof(x)x32PC机中,常见的有:char1Bshort2Bint4Blong4Bfloat4Bdouble8B数组:intarr[10];10int类型的内存区域。sizeof(arr)10*sizeof(int)40B这些内置的int如unsignedintx;sizeof(x)4B,有无符号,在占用内存空间的大小上是一样的。其它的也是如此。构造structA{intx;inty;};Amystruct;表示声明有一个构造类型Aintmystruct。则sizeof(mystruct)sizeof(mystruct.x)+sizeof(mystructy)sizeof(int)+sizeof(int)8B这些类型的大小,对理解内存中数据构造,很有帮助,请记住。些变量都是临时,一量出了函数,我们都不能用它。事实上到栈中。堆堆是相对于栈的,前面说到栈的大小或许为1MB,而用户能用到的内存或许有2GB,因此2G2G。(接近2G,是我的理解,没有在其它书中看到类似的结论,说错了,你别笑话我。)堆主要有两个作用:堆主要有两个作用:1、欲安排内存空间的大小,或称长度,可以是变量,这意味着这个大小,在安排前,可以“安排前”,在安排完了以后,这段内存的大小理论上还是不行以改大小的,除非释放掉或用一些特别的方法。2mallocfree。比方:#include<stdlib.h>/**/intsize=10*sizeof(int);int*pInt=(int*)malloc(size);size的内存,将安排到的那段内存,标识成一系列int型数据,并将这段内存的地址,赋值给一个int型指针pInt,这样,通过pInt就可以把握这段内存了。我们知道在栈中,可以通过数组,也能达上述的效果,如下:intarr[10];他们是有区分的:2、在大小上,前者总共能安排的内存接近2GB,可以说很大了,而后者,其栈总的大小1MB1MB1M-安排前栈的大小。1(2、在大小上,前者总共能安排的内存接近2GB,可以说很大了,而后者,其栈总的大小1MB1MB1M-安排前栈的大小。1M的话,只能选择前者。3、在作用范围上,前者的内存地址可以用一个指针表示,假设这个指针是全局变量的话,则始终可以把握这块内存了,事实上,只要这块内存不被释放,那么在程序任何地方4、在“3、”中,似乎感觉堆很好,但隐蔽了一个重要的麻烦,那就是内存释放,由于堆的实上这段内存则不会被再用到,直到程序完毕,比方我申请了200M的内存,没释放,这种铺张还是很可观的。针对于他们的区分,我们可以有一个结论:同时满足:临时性,小的(1M),更快的内存安排用栈,(3条“更快”由于现代机器够快,两种方式都会满足),否则用堆。试时会常常考到。假设堆安排不成功的话,则返回NULL。free;如下:int*pInt=(int*)malloc(size);/*pInt做一些操作*/free(pInt);静态区域:该区域主要存储全局变量和静态变量。该区域内存储的变量在程序的整个运行期间都存在,free就被系统收回。全局变量:只要在任何一个函数外声明的变量就是全局变量,在任何地方都可以被访问到。前都是固定的,不会有别的变量占用这块内存。全局变量:只要在任何一个函数外声明的变量就是全局变量,在任何地方都可以被访问到。静态变量:声明类似于如下:staticintstatic_value=0;1static,说明它是静态变量.它的函数中访问。见如下程序:2它的函数中访问。见如下程序:voidTestStatic{staticinti=5;i++;}voidmain{TestStatic;TestStatic;}TestStatic时。其变化如以下图:运行其次个TestStatic时,如以下图:一些存储常量的地方:比方:char*一些存储常量的地方:比方:char*p=“abcdefg”;这里p也是有值的,不过一般都不会这么写。正确的方法是charp[]=“abcdefg”;常用操作内存的库函数:要把握内存,主要有复制、设值、比较等操作,共对应库函数如下:1、复制void*memcpy(void*dest,constvoid*src,size_tcount)srccount的一段内存上的内容,复制到地址为dest开头的一段内存中。2、比较intmemcmp(constvoid*buf1,constvoid*buf2,size_tcount)buf1buf2开头的两段内存相互比较,要比较的长度为count,返回值>0buf1大,<0buf2的,==0,则表示这两段内存的内存一样。#include<string.h>#include<stdio.h>){6intint_arr1[]={1,2,3,4};7intint_arr2[]={1,2,3,4};intresult;);result=memcmp(first,second,19);<0));==0)););int_arr1[1],int_arr2[0],int_arr2[1]);*2);<0)==0));23}3、设值void*memset(void*dest,intc,size_tcount)dest,count的一段内存的每个字节,全部赋值为c。一般来说,该函0。即memset(buffer,0,buffer_size);memory.h中声明,假设编译器提示找不到这些函数,则要include它。内存构造知道这么多,已经差不多了。这局部内容,请认真体会。2、指针前面已经说过,内存都有地址编号的,这个地址编号是从0x00000000到0xFFFFFFFF,这样我们知道了某一个地址就可以访问这段内存再将一个具体的地址编号赋值给它,是否利用这个整型变量就可以访问该段内存呢?答案是确定的,但一般我们不这样做,在C语言中,引进了一个专业名词:指针指针有两个方面的属性:指针有两个方面的属性:1、指针的值就是地址编号。2对于1、的理解,你可以把指针想像成整型变量,事实上,指针确实可以和整型变量互换,比方:char*p=(char*)(5);inti=(int)p;如图:0x00000005的一段内存是不行以被访问的。对于2、的理解,我们可以这样认为:描述一段内存,则必需指明其开头地址,及长度。这个指针类型,就是表示这段内存有多长,及这段内存到底是干什么用的,比方:intvlaue=1234;int*p=&value;可以这样理解pvaluesizeof(int),这段内存就表示int类型的值。既然指针同整型变量类似,那么指针本身所占内存也是可以确定的,它的值范围在0-4G,4B就够了。确实,在C语言中,32PC4,比方:char*p1;int*p2;structA{intx;inty;}A*p4;那么sizeof(p1)、sizeof(p2)、sizeof(p3)4B,但sizeof(*p1)、sizeof(*p2)、sizeof(*p3)的值应当等同于sizeof(char)、sizeof(int)、sizeof(structA)struct*/即1,4,8

/*这里有一点请留意:Ax,y的大小之和。但有时候状况比较特别,如structB{intx;inty;charz;};此时sizeof(B)9,而是12,这是由于编译器为了考虑效率的问题,一般要将内存对齐,所48的整数倍。这种内存对齐机制可以在编译器中设置。这种对齐机制不要求把握,知道有这么回事就行,面试时有可能会被问到。所以提一下。看到这里,你应当能理解,指针其实就是一个变量,只是这个变量的值就是内存地址而已。我们知道一般变量是保存到栈中的,那么指针本身也将是保存到栈中,也是可以取地址的,甚至其地址也可以被赋值给另一个指针,这称之为指向指针的指针,比较好玩吧。比方:voidmain{inti=5;int*p=&i;int**p2=&p;}由此也可以体会指针和引用的区分在栈中定义一个变量i0x0012ff7csizeof(int)(4B),那么其下变量p的地址就是4即该0x0012ff7c0x0012ff78。如图:是一个指针。固然指向指针的指针是一个相比照较高级的话题,不理解也没关系。的内存地址就行了,可以这样定义指针:void*p;表示有一个指针,它可以指向某段内存,但不知这段内存具体表示什么,也不知道其长度,即:sizeof(*p)是无效的。机制。针对void*的指针有这样的特点:void*类型的指针,可以被任何其它类型的指针赋值,比方:inti=5;int*p1=&i;void*p2=p1;留意:1、void如用于函数定义时,表示如下:voidfun(void){/*…*/}表示有一个函数,没有参数,也没有返回值。其中表示没有参数时,也可以省略void。2、由于void没有类型,不知道占用空间的大小,所以不能定义成变量,只能作为指针的类型。我们是否可以引申一下,要定义成变量的,其类型必需明确大小。(这是我自己的理解,未在其它书中看到类似的结论)3、字符串处理这是一个大家常常遇到,但又似懂非懂的主题。这里面有几个概念如下:(1)、字符变量(2)、字符指针(3)、字符数组(4)、字符串电脑是外国人制造的,开头时他们需要显示在屏幕上字符只是字母、数字及一些标点符号,把这些字符全部加在一起,也只有100来个(哪有我们汉字,这样博大精深啊)。由于计算机都由二进制数字组成,这样,他们就规定类似于0A,1B…之类的编码规章。后来这个编码规章形成一个统一的标准,我们称之为ASCII码。ASCII表格:0x00-0xFFCinti=„a‟;charc=0x41;这都没问题,i0x61,c的值是‟A‟,之所以可以这样做,是由于它们的存储方式都是一样的。如图:0127的数据是一回事,那么1„2‟的值为‟3‟„a‟+3的值为‟d‟也应当好理解了。一个有符号位的字节能表示的大小为一个有符号位的字节能表示的大小为-128-127,所以在ASCII中,用一个字节就可以表ASCII1B。一般处理字符,不行能是单个字符,而是多个字符的组合,在C语言中,称之为字符串。字符串有很多字符组成,但到底有多少个呢?在C0结尾的,这个0ASCII0NULL。比方,字符串:“abc”在内存中就是这样存储61626300 /*16进制*/字符串,是很多字符连续排序在一起的。因此,可以用数组表示:charbuffer[256];256个元素的数组,元素的类型为char型,所以该数组占用空间为256*sizeof(char)256B这称之为字符数组。有时定义时,可以初使化一下:charbuffer[256]={0};charbuffer[]=“abc”;charbuffer[]=“abc”;表示将字符串”abc”0buffer,即此时,sizeof(buffer)4B义一个字符指针:char*p=buffer;表示定义一个字符指针,让其指向数组buffer的地址。字符指针除了便利定位于每一个字符外处理字符串主要用的函数有:size_tstrlen(constchar*string)表示取字符串的长度,即字符数留意:const:表示不转变此字符串的内容。size_t不同的编译器定义可能不一样,但一般都是unsignedint类型。size_t不同的编译器定义可能不一样,但一般都是unsignedint类型。charcharstr=“abc”;sizeof(str)4,见前面说明。strlen(str)3strlen0char*strcpy(char*strDestination,constchar*strSource)strSourcestrDestination中去strDestinationstrSource能会掩盖其后的内容。所以使用时要留意。intstrcmp(constchar*string1,constchar*string2)表示比较两个字符串是否相等,假设返回值>0string1大,<0string2大,==0则相等由于字符串都处于内存中,所以对字符串的赋值及比较操作,完全可以用内存操作的函数,memcpy,memcmp等代替。单个字符的输出,可以这样charc=„a‟;printf(“%c”,c);字符串的输出,可以这样charstr[]=“abc”;printf(“%s”,s);要将一个整数转换成字符串,可以这样charstr[64];inti=100;sprintf(str,“%d”,i);反过来,要将字符串转换成整型,有函数atoi,如下:i=atoi(str);链表:链表都是类比于数组的。数组在内存空间每个元素的位置都是连续的,即&a[i]+sizeof(a[i])必定与&a[i+1]相等。4个数,3,5,9,2。用数组可以表示如下:inta[4]={3,5,9,2};这样表示有几点局限性:1、很明显,这是定义在栈中,前面争论过栈最大不超过1M,假设数量很多,以致于总的需要空间超过1M,就不行了。2位置插入一个元素,则插入点后面的元素都应当相应后移一位,这造成效率上的降低。3、不便利增加一个元素,这里定义了41个元素,这种方式则难办了。4会造成大量内存铺张。数组在内存存储的位置,见图:为了解决以上问题,我们可以引入链表。12、找到下一个元素的线索在数组a中,a[1]确定是紧接排列在a[0]的后面。前面已经说过,全部的元素严密地排一起不愿定是好事,那就分开吧。这样我们就可以令a[1]不紧靠着a[0],但这又引入了一问题,以前大家做邻居的时候,访问完a[0]a[1]a[1]搬走了,怎么办?QQa[0]了。同样,a[2]12、找到下一个元素的线索依据这样两个属性,我们可以这样定义元素structnode{int data;structnode*next;/*表示定义一个指针,其指向一个node类型的构造体*/};前面说过,a[1]的地址由a[0]保存,那a[0]的地址由谁保存,答案是没人给他保存,所以必需登记来,我们可以用一个头指针记录元素a[0]的地址,即定义一个指针:structnode*pHead=NULL;structnode*structnode*CreateNode(intdata){structnode*p=(structnode*)malloc(sizeof(structnode));p->data=data;p->next=NULL;returnp;}node*pNode=pHead;/*node*pNode=pHead;/*node*/node*pTemp;/*临时性的*/for(inti=0;i<4;i++){pTemp=CreateNode(a[i]);if(pNode==NULL){/*第一次*/pHead=pTemp;}else{}

pNode->next=pTemp;pNode=pTemp;}到此链表组建完成,如图:pNodepNode=pHead;while(pNode!=NULL){printf(“%d”,pNode->data);pNode=pNode->next;}node之后,插入一个元素,如下voidInsert(structnode*pNode,intnew_data){structnode*p=CreateNode(new_data);structnode*pTemp=pNode->next;pNode->next=p;p->next=pTemp;}如图:完整的例子代码如下:#include<stdio.h>#include<stdlib.h>/*定义一个结点*/structnode{int data;structnode* next;};/*创立一个结点*/structnode*CreateNode(intdata){structnode*p=(structnode*)malloc(sizeof(structnode));p->data=data;p->next=NULL;returnp;}voidmain{structnode*pHead=NULL; /*头指针,开头时为NULL*/structnode*pNode=pHead; /*指向每个结点*/structnode*pTemp;intdata;/*建立链表*/while(1){scanf(“%d“,&data); /*输入整数,0则表示完毕*/if(data==0)break;pTemp=CreateNode(data);if(pNode==NULL){}else{}

pHead=pTemp;pNode->next=pTemp;pNode=pTemp;}/*遍历整个链表*/pNode=pHead;while(pNode!=NULL){printf(“%d“,pNode->data);pNode=pNode->next;}/*mallocfree*/while(pNode!=NULL){pTemp=pNode->next;free(pNode);pNode=pTemp;}}往下面看。复习大纲中的代码及补充代码如下:#include<stdio.h>#include<stdlib.h>structlink{intdata;structlink*next;};intn; /*统计结点总数*//*创立整个链表*/structlink*creat(){/*head表示链表的头,将会作为返回值*//*p1,p2都表示指向某个结点*/structlink*head,*p1,*p2;n=0;/*0*//*要求用户输入第一个值*/p1=p2=(structlink*)malloc(sizeof(structlink));scanf(“%d“,&p1->data);/*BUGp1->data0的话,就直接返回dd为c得到内存将无法释放,形成内存泄漏,但假设仅是演示,则无关大雅*/head=NULL;while(p1->data!=0)/*0作为推断条件*/{n=n+1; /*1*/if(n==1) /*第一次,则在头中,进展记录*/head=p1;else /*前一个结点中的指针,指向当前结点*/p2->next=p1;p2=p1; /*跳过当前结点*//*连续要求用户输入*/p1=(structlink*)malloc(sizeof(structlink));scanf(“%d“,&p1->data);}/*最终一个结点中的指针,要求为NULL*/p2->next=NULL;return(head);}voidmain{structlink*head,*p,*temp;head=creat;/*遍历*/p=head;while(p!=NULL){printf(“%d“,p->data);p=p->next;}printf(“\nTotle:%d\n“,n);/*释放*/p=head;while(p!=NULL){temp=p->next;free(p);p=temp;}}大纲中合并两个有序链表的说明如下:structlk{intdata;structlk*next;}/*将两个本身为升序的链表,合并后成为一个的链表*/structlk*merge(a,b)structlk*a,*b; /*参数的表示方式,相当于structlk*merge(structlk*a,structlk*b)*/{structlk*c,*p;/*a,b两链表的第一个结点,取出其值小一点的结点*/if(a->data<b->data){c=a;a=a->next;}else{}p=c;

c=b;b=b->next;while(a!=NULL&&b!=NULL){/*a,b中每一个结点*/if(a->data<b->data){}else{}

p->next=a;a=a->next;p->next=b;b=b->next;p=p->next;}*/

/*a,b中有哪一个提前遍历完,则另一个剩余的局部,就被挂在的链表中末if(a==NULL)p->next=b;elsep->next=a;/*返回生成的链表头*/return(c);}复习大纲中的一些学问点理解1、如何理解当a=2时a+=a-=a*a结果为-4a+=a-=a*=a结果为0a/=a+a结果为0解答:a+=a-=a*a;相当于a+=(a-=(a*a));1a2;2、计算:a*a,==〉2*24;3、计算:a-=4,==〉a=a-4==〉a=2-4,结果为-2,此时a的值为-2;4、计算:a+=-2,==〉a=a+2==〉a=-2+(-2),结果为-4,此时a的值为-4;a+=a-=a*=a;相当于a+=(a-=(a*=a));1a的值为-4;(这里假设该式是在前面的式子运行完后,接着运行,但后来感觉,该式可能是独立的,与前面的式子无关,无论初值如何,不影响理解)2、计算:a*=a,==a=a*a==a=(-4)*(-4),结果为16a的值为16;3、计算:a-=16==〉a=a-160,此时a的值为0;4、计算:a+=a;==〉a=a+a0,此时a的值为0;a+=(a-=(a*=a)); 0。缘由在于a-=(a*=某个值);相当于a减去自身,0。a/=a+a;相当于a/=(a+a);1a2;2、计算:a+a4;此时a2;3、计算:a/=4;==>a=a/4;==>a=2/4;==>a=0;0;22、冒泡排序源程序解释如下:#include<stdio.h>#defineSIZE10/**/voidswap(int*p1,int*p2){inttemp;temp=*p1;*p1=*p2;*p2=temp;}/**/voidsort(int*array,intn){inti,j;/*这段循环可以这样理解:假设n10a[0]a[9]1步,将[0,9]a[9]中2步,将[0,8]a[8]中...n步,将[0,0]a[0]中*/for(i=1;i<=n-1;i++)for(j=0;j<=n-i-1;j++){if(array[j]>array[j+1]) /*>*/swap(&array[j],&array[j+1]);}/**//*forfor(i=0;i<n;i++)for(j=0;j<i;j++){if(array[j]>array[j+1])swap(&array[j],&array[j+1]);}*/}main{inti,a[SIZE];/*10个数*/for(i=0;i<=SIZE-1;i++)scanf(“%d“,a+i);/**//*a[0]=10;a[1]=70;a[2]=20;a[3]=14;a[4]=60;a[5]=19;a[6]=20;a[7]=256;a[8]=23;a[9]=86;*/sort(a,SIZE);/**/for(i=0;i<=SIZE-1;i++)printf(“%d\n“,a[i]);}1、关于静态变量其可运行源码如下:#include<stdio.h>longf(n)intn;{staticx=2;if(n==0)return(1);else{x=x*n;return(x);}}main{/*printf(“%d\n“,f(0)+f(1)+f(2)+f(3));等同于下面式子*/intf0,f1,f2,f3;f0=f(0); /*运行前:x为2,运行后:x为2,f0为1*/f1=f(1); /*运行前:x为2,运行后:x为2,f0为2*/f2=f(2); /*运行前:x为2,运行后:x为4,f0为4*/f3=f(3); /*运行前:x为4,运行后:x为12,f0为12*/printf(“%d\n“,f0+f1+f2+f3);}2、关于变量作用域,其源码如下:#include<stdio.h>intx=4;voida;voidb;voidc;voidd(x);main{

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论