cc++概念区别.docx
- 文档编号:26653315
- 上传时间:2023-06-21
- 格式:DOCX
- 页数:11
- 大小:20.66KB
cc++概念区别.docx
《cc++概念区别.docx》由会员分享,可在线阅读,更多相关《cc++概念区别.docx(11页珍藏版)》请在冰豆网上搜索。
cc++概念区别
数组指针和指针数组的区别
数组指针(也称行指针)
定义int(*p)[n];
()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。
也就是说执行p+1时,p要跨过n个整型数据的长度。
如要将二维数组赋给一指针,应这样赋值:
inta[3][4];
int(*p)[4];//该语句是定义一个数组指针,指向含4个元素的一维数组。
p=a; //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0]
p++; //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]
所以数组指针也称指向一维数组的指针,亦称行指针。
指针数组
定义int*p[n];
[]优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素。
这里执行p+1是错误的,这样赋值也是错误的:
p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]...p[n-1],而且它们分别是指针变量可以用来存放变量地址。
但可以这样*p=a;这里*p表示指针数组第一个元素的值,a的首地址的值。
如要将二维数组赋给一指针数组:
int*p[3];
inta[3][4];
for(i=0;i<3;i++)
p[i]=a[i];
这里int*p[3]表示一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2]
所以要分别赋值。
这样两者的区别就豁然开朗了,数组指针只是一个指针变量,似乎是C语言里专门用来指向二维数组的,它占有内存中一个指针的存储空间。
指针数组是多个指针变量,以数组形式存在内存当中,占有多个指针的存储空间。
还需要说明的一点就是,同时用来指向二维数组时,其引用和用数组名引用都是一样的。
比如要表示数组中i行j列一个元素:
*(p[i]+j)、*(*(p+i)+j)、(*(p+i))[j]、p[i][j]
指针函数和函数指针的区别
这两个概念都是简称,指针函数是指带指针的函数,即本质是一个函数。
我们知道函数都又有返回类型(如果不返回值,则为无值型),只不过指针函数返回类型是某一类型的指针。
其定义格式如下所示:
返回类型标识符*返回名称(形式参数表)
{函数体}
返回类型可以是任何基本类型和复合类型。
返回指针的函数的用途十分广泛。
事实上,每一个函数,即使它不带有返回某种类型的指针,它本身都有一个入口地址,该地址相当于一个指针。
比如函数返回一个整型值,实际上也相当于返回一个指针变量的值,不过这时的变量是函数本身而已,而整个函数相当于一个“变量”。
例如下面一个返回指针函数的例子:
函数指针
函数指针是指向函数的指针变量。
因而“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。
这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。
如前所述,C在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。
有了指向函数的指针变量后,可用该指针变量调用函数,就如同用指针变量可引用其他类型变量一样,在这些概念上一致的。
函数指针有两个用途:
调用函数和做函数的参数。
函数指针的说明方法为:
数据类型标志符(指针变量名)(形参列表);
注1:
“函数类型”说明函数的返回类型,由于“()”的优先级高于“*”,所以指针变量名外的括号必不可少,后面的“形参列表”表示指针变量指向的函数所带的参数列表。
例
intfunc(intx);/*声明一个函数*/
int(*f)(intx);/*声明一个函数指针*/
f=func;/*将func函数的首地址赋给指针f*/
赋值时函数func不带括号,也不带参数,由于func代表函数的首地址,因此经过赋值以后,指针f就指向函数func(x)的代码的首地址。
注2:
函数括号中的形参可有可无,视情况而定。
下面的程序说明了函数指针调用函数的方法:
例一、
#include
intmax(intx,inty){return(x>y?
x:
y);}
voidmain()
{
int(*ptr)(int,int);
inta,b,c;
ptr=max;
scanf("%d,%d",&a,&b);
c=(*ptr)(a,b);
printf("a=%d,b=%d,max=%d",a,b,c);
}
ptr是指向函数的指针变量,所以可把函数max()赋给ptr作为ptr的值,即把max()的入口地址赋给ptr,以后就可以用ptr来调用该函数,实际上ptr和max都指向同一个入口地址,不同就是ptr是一个指针变量,不像函数名称那样是死的,它可以指向任何函数,就看你像怎么做了。
在程序中把哪个函数的地址赋给它,它就指向哪个函数。
而后用指针变量调用它,因此可以先后指向不同的函数,不过注意,指向函数的指针变量没有++和--运算,用时要小心。
不过,在某些编译器中这是不能通过的。
这个例子的补充如下。
应该是这样的:
1.定义函数指针类型:
typedefint(*fun_ptr)(int,int);
2.申明变量,赋值:
fun_ptrmax_func=max;
也就是说,赋给函数指针的函数应该和函数指针所指的函数原型是一致的。
例二、
#include
voidFileFunc()
{
printf("FileFunc\n");
}
voidEditFunc()
{
printf("EditFunc\n");
}
voidmain()
{
void(*funcp)();
funcp=FileFunc;
(*funcp)();
funcp=EditFunc;
(*funcp)();
}
关于函数指针数组的定义
关于函数指针数组的定义方法,有两种:
一种是标准的方法;一种是蒙骗法。
第一种,标准方法:
{
分析:
函数指针数组是一个其元素是函数指针的数组。
那么也就是说,此数据结构是是一个数组,且其元素是一个指向函数入口地址的指针。
根据分析:
首先说明是一个数组:
数组名[]
其次,要说明其元素的数据类型指针:
*数组名[].
再次,要明确这每一个数组元素是指向函数入口地址的指针:
函数返回值类型(*数组名[])().请注意,这里为什么要把“*数组名[]”用括号扩起来呢?
因为圆括号和数组说明符的优先级是等同的,如果不用圆括号把指针数组说明表达式扩起来,根据圆括号和方括号的结合方向,那么*数组名[]()说明的是什么呢?
是元素返回值类型为指针的函数数组。
有这样的函数数祖吗?
不知道。
所以必须括起来,以保证数组的每一个元素是指针。
}
再给出常用的C变量的定义方式:
a)一个整型数(Aninteger)
b)一个指向整型数的指针(Apointertoaninteger)
c)一个指向指针的的指针,它指向的指针是指向一个整型数(Apointertoapointertoaninteger)
d)一个有10个整型数的数组(Anarrayof10integers)
e)一个有10个指针的数组,该指针是指向一个整型数的(Anarrayof10pointerstointegers)
f)一个指向有10个整型数数组的指针(Apointertoanarrayof10integers)
g)一个指向函数的指针,该函数有一个整型参数并返回一个整型数(Apointertoafunctionthattakesanintegerasanargumentandreturnsaninteger)
h)一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数(Anarrayoftenpointerstofunctionsthattakeanintegerargumentandreturnaninteger)
答案是:
a)inta;//Aninteger
b)int*a;//Apointertoaninteger
c)int**a;//Apointertoapointertoaninteger
d)inta[10];//Anarrayof10integers
e)int*a[10];//Anarrayof10pointerstointegers
f)int(*a)[10];//Apointertoanarrayof10integers
g)int(*a)(int);//Apointertoafunctionathattakesanintegerargumentandreturnsaninteger
h)int(*a[10])(int);//Anarrayof10pointerstofunctionsthattakeanintegerargumentandreturnaninteger
const、volatile区别
1、const
下面的声明都是什么意思?
constinta;
intconsta;
constint*a;
int*consta;
intconst*aconst;
/******/
前两个的作用是一样,a是一个常整型数。
第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。
第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。
最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。
顺带提一句,即使不用关键字const,也还是能很容易写出功能正确的程序,那为什么还要如此看重关键字const呢?
我也如下的几下理由:
i,关键字const的作用是为给读你代码的人传达非常有用的信息,实际上,声明一个参数为常量是为了告诉了用户这个参数的应用目的。
如果你曾花很多时间清理其它人留下的垃圾,你就会很快学会感谢这点多余的信息。
(当然,懂得用const的程序员很少会留下的垃圾让别人来清理的。
)
ii, 通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。
iii, 合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。
简而言之,这样可以减少bug的出现。
2、Volatile
这个限定词告诉编译器,变量可以被程序外的某个东西修改,这些东西包括操作系统,硬件或是同时执行的线程等。
尤其是,voliate限定词会告诉编译器,不对该变量进行任何优化,并且总是重新加载来自该变量的内存单元的值。
精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。
i, 并行设备的硬件寄存器(如:
状态寄存器)
ii, 一个中断服务子程序中会访问到的非自动变量(Non-automaticvariables)
iii, 多线程应用中被几个任务共享的变量
下面是volatile变量的几个例子:
1;一个参数既可以是const还可以是volatile吗?
解释为什么。
2;一个指针可以是volatile吗?
解释为什么。
1;是的。
一个例子是只读的状态寄存器。
它是volatile因为它可能被意想不到地改变。
它是const因为程序不应该试图去修改它。
2;是的。
尽管这并不很常见。
一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。
留一个问题:
constvolatileinti=10;这行代码有没有问题?
如果没有,那i到底是什么属性?
回答一:
没有问题,例如只读的状态寄存器。
它是volatile,因为它可能被意想不到地改变;它是const,因为程序不应该试图去修改它。
volatile和const并不矛盾,只是控制的范围不一样,一个在程序本身之外,另一个是程序本身。
回答二:
没问题,const和volatile这两个类型限定符不矛盾。
const表示(运行时)常量语义:
被const修饰的对象在所在的作用域无法进行修改操作,编译器对于试图直接修改const对象的表达式会产生编译错误。
volatile表示“易变的”,即在运行期对象可能在当前程序上下文的控制流以外被修改(例如多线程中被其它线程修改;对象所在的存储器可能被多个硬件设备随机修改等情况):
被volatile修饰的对象,编译器不会对这个对象的操作进行优化。
一个对象可以同时被const和volatile修饰,表明这个对象体现常量语义,但同时可能被当前对象所在程序上下文意外的情况修改。
另外,LS错误,const可以修饰左值,修饰的对象本身也可以作为左值(例如数组)
C结构体、C++结构体和C++类的区别
C结构体与C++结构体区别
C结构体只是一个复杂数据类型,只能定义成员变量,不能定义成员函数(不要跟我说函数指针),不能用于面向对象编程
C++中 struct 与 class的区别:
对于成员访问权限以及继承方式,class中默认的是private,而struct中则是public.class还可以用于表示模板类型,struct则不行。
#include"filename.h"和#include
#include"filename.h"是指编译器将从当前工作目录上开始查找此文件,若找不到,再从标准库目录查找;
#include
ISO的七层模型是什么?
tcp/udp是属于哪一层?
tcp/udp有何优缺点?
答:
应用层、表示层、会话层、运输层、网络层、物理链路层、物理层
tcp/udp属于运输层
TCP服务提供了数据流传输、可靠性、有效流控制、全双工操作和多路复用技术等。
与TCP不同,UDP并不提供对IP协议的可靠机制、流控制以及错误恢复功能等。
由于UDP比较简单,UDP头包含很少的字节,比TCP负载消耗少
tcp:
提供稳定的传输服务,有流量控制,缺点是包头大,冗余性不好
udp:
不提供稳定的服务,包头小,开销小
static全局变量与普通的全局变量有什么区别?
static局部变量和普通局部变量有什么区别?
static函数与普通函数有什么区别?
答:
全局变量(外部变量)的说明之前再冠以static就构成了静态的全局变量。
全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。
这两者在存储方式上并无不同。
这两者的区别虽在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。
而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。
由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。
从以上分析可以看出,把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。
把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。
static函数与普通函数作用域不同。
仅在本文件。
只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。
对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件
static全局变量与普通的全局变量有什么区别:
static全局变量只初使化一次,防止在其他文件单元中被引用;
static局部变量和普通局部变量有什么区别:
static局部变量只被初始化一次,下一次依据上一次结果值;
static函数与普通函数有什么区别:
static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝
程序的局部变量存在于()中,全局变量存在于()中,动态申请数据存在于()中。
答:
栈;静态区;堆
c语言变量存储区
一般认为在c中分为这几个存储区:
1.栈--有编译器自动分配释放
2.堆--一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收
3.全局区(静态区)--全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。
程序结束释放。
4.另外还有一个专门放常量的地方。
程序结束释放
在函数体中定义的变量通常是在栈上,用malloc,calloc,realloc等分配内存的函数分配得到的就是在堆上。
代码:
inta=0;//全局初始化区
char*p1;//全局未初始化区
main()
{
intb;//栈
chars[]="abc";//栈
char*p2;//栈
char*p3="123456";//123456在常量区,p3在栈上。
staticintc=0;//全局(静态)初始化区
p1=(char*)malloc(10);
p2=(char*)malloc(20);
//分配得来得10和20字节的区域就在堆区。
strcpy(p1,"123456");
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- cc 概念 区别