c++总结(一)

C++编程基础与对齐规则详解
本文详细探讨了C++中类的内存对齐规则,解释了按1字节和4字节对齐时sizeof(CTest)的值。同时,介绍了C++中的static变量的作用,以及引用与指针的区别。还涉及头文件保护、include语法、实时系统特性、全局与局部变量内存区别、平衡二叉树概念和堆栈溢出原因。此外,文章讨论了预编译、const和volatile关键字的用途,以及数组、指针、静态变量与全局变量的内存分配。最后,讲解了如何用两个栈实现队列功能,以及C++中静态变量在不同模块的处理和链表节点删除的方法。

1, 若char是一字节,int是4字节,指针类型是4字节,代码如下:

Class  CTest

{

Public:

CTest():m_chData(‘\0’),m_nData(0)

{

}

Virtual void mem_fun(){}

 

private:

   char m_chData;

   int m_nData;

   static char s_chData; //

};

Char CTest::s_chData=’\0’;

 

问:(1)若按1字节对齐sizeof(CTest)的值是多少? 9

    虚指针 (4)  +  char (1) + int(4) =9; 

   (2)若按4字节对齐sizeof(CTest)的值是多少? 12

  虚指针(4)+char(1+3)+int(4)=12;


static 的 作用

1)在函数体,一个被声明为staic的变量在这一函数被调用过程中维持其值不变。

2)在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但是不能被模块外其它函数访问。

它是一个本地的全局变量。

3)在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。


引用和指针的区别?

1)引用必须被初始化,指针不必。

2)引用初始化以后不能被改变,指针可以改变所指的对象。

3)不存在指向空值的引用,但是存在指向空值的指针。

指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序可读性差,

而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。

流操作符<< 和 >>,赋值操作符=的返回值,拷贝构造函数的参数,赋值操作符=的参数,其它情况都推荐使用引用。


.h 头文件中的 ifndef/define/endif 的作用?

防止该头文件被重复引用。


#include和#include“file.h”的区别?

前者是从 Standard Library 的路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h

描述实时系统的基本特性

在特定的时间内完成特定的任务,实时性与可靠性。


全局变量和局部变量在内存中是否有区别?如果有,是什么区别?

全局变量存储在静态数据区,局部变量在堆栈中。

什么是平衡二叉树

左右子树都是平衡二叉树 且 左右子树 的 深度差值 的 绝对值 不大于 1.

堆栈溢出一般是由什么原因导致的?

没有回收垃圾资源

层次太深的递归调用


冒泡排序时间复杂度?

O(n^2)


什么函数不能声明为虚函数?

constructor  构造函数


不能做switch()的参数类型?

SWITH(表达式),表达式可以是整型、字符型以及枚举类型等表达式

switch()的参数类型不能是 实型

除了整型,枚举类型,字符型,其他的都不行。譬如:字符串,浮点型这些都不可以作为switch的参数类型。


##局部变量能否和全局变量重名?

能,局部会屏蔽全局。要用全局变量,需要使用 “::”

局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不是全局变量


##如何引用一个已经定义过的全局变量?

可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件的方式来引用某个在头文件中声明的全局变量,假定你将那个变量写错了,那么在

编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在链接期间报错。


##解释堆和栈的区别


1)申请方式

stack 有系统自动分配。例如,声明在函数中的一个局部变量 int b;系统自动在栈中为b开辟空间

heap:需要程序员自己申请,并指明大小,在c中malloc 函数

p1=(char *)malloc(10);

p2=new char[10];

p1,p2 本身是在栈之中的。

2)申请后系统的响应

栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。

堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统受到程序申请时,会遍历该链表,寻找第一个空间大于所申请

空间的堆节点,然后将该节点从空闲界定链表中删除,并将该节点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,

代码中的delete 语句 才能正确的释放本内存空间,另外,由于找到的堆节点的大小不一定正好等于申请的大小,系统会自动的将多余的那一部分重新放入空闲链表之中。


3)申请大小的限制

栈:向低地址扩展的数据结构,是一块连续的内存区域。这句话的意思是,栈顶的地址和栈的最大容量是系统预先规定好的,能从栈获得的空间较小

堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存的、链表的遍历方向是由低地址向高地址。

堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

4)申请效率比较:

栈:有系统自动分配,速度快,但程序员无法控制。

堆:只有new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。

5)堆和栈中的存储内容

栈:在函数调用时,第一个进栈的是主函数中后一条指令的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,

然后是函数中的局部变量。注意静态变量是不入栈的。

但本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由改点继续运行。

堆:一般是在堆的头部用一个字节存放堆的大小,堆中的具体内容由程序员安排。


6)存续效率比较

char s1[]=“aaaaaaaaa”;

char *s2="bbbbbbbbbb";

aaaaaaaaa是在运行时刻赋值的

而bbbbbbbbbb是在编译时就确定的。

但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。

比如:

void main()

{

char a=1;

char c[]="1234567890";

char *p="1234567890";

a=c[1];

a=p[1];

return;

}

第一种在读取时直接就把字符串中的元素读到寄存器cl中,第二种则要先把指针值读到edx中,在根据edx读取字符,显然慢了。。


##什么是预编译,何时需要预编译?

预编译又称为预处理,是做些代码文本的替换工作。处理#开头的指令,比如拷贝#include包含的文件代码。#define 宏定义的替换,条件编译等等,

就是为编译做的预备工作的阶段,主要处理#开始的预编译指令,预编译指令指示了在程序正式编译前就有编译器进行的操作。

可以放在程序中的任何位置。

编译系统在对程序进行通常编译之前,先进行预处理,c提供的预处理功能主要有一下三种:

1)宏定义

2)文件包含

3)条件编译


##关键字const含义?

const 意味着只读,

int b = 500; 
const int* a = &              [1] 
int const *a = &              [2] 
int* const a = &              [3] 
const int* const a = &      [4] 

[1]和[2]的情况相同,都是指针所指向的内容为常量(const放在变量声明符的位置无关),这种情况下不允许对内容进行更改操作,如不能*a = 3 ;[3]为指针本身是常量,而指针所指向的内容不是常量,这种情况下不能对指针本身进行更改操作,如a++是错误的;[4]为指针本身和指向的内容均为常量。




##volatile 有什么含义,并给出三个不同的例子

一个定义为volatile 的变量是说这个变量可能会被意想不到的改变,这样,编译器就不会去假设这个变量的值了。

精确的说,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份,

下面是volatile变量的几个例子

1)并行设备的硬件寄存器

2)一个中断服务子程序中会访问道德非自动变量

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


一个参数既可以是const还可以是volatile吗?解释为什么?

是的 一个例子是 只读的状态寄存器。它是volatile因为它可能被意想不到的改变,它是const因为程序不应该试图去修改它


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

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


3)下面的函数有什么错误:

int square(volatile int *ptr)

{

return *ptr **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;

}



##三种基本的数据模型

层次模型   网状模型  关系模型


##结构和联合有何区别

呵呵


##描述内存分配凡是以及他们的区别?

1)静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如,全局变量,static变量

2)栈上创建

3)在堆上分配。//使用灵活,问题多


##const与#define相比,有何优点?

1)const常量有数据类型,而宏常量没有数据类型,编译器可以对前者进行类型安全检查。对后者只进行字符替换,没有类型安全检查,字符替换可能产生意想不到的错误

2)有些调试工具可以对const常量进行调试,但是不能对宏常量进行调试。


##数组和指针的区别

当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针

char a[]="hello world";

char *p=a;

cout<<sizeof(a)<<endl;//12

cout<<sizeof(p)<<endl;//4

计算数组和指针的内存容量

void Func(char a[100])

{

cout<<sizeof(a)<<endl;//4而不是100

}



##分别写出BOOL,int,float ,指针类型 变量 a 与 “零”的比较语句

BOOL  if(!a) or if(a)

int if(a==0)

float const EXPRESSION EXP=0.000001 //typedef float EXPRESSION;

if(a<EXP&&a>EXP)

pointer: if(a!=NULL) or if(a==NULL)


##如何判断一段程序是由C编译程序还是有C++编译程序编译的?

#ifdef __cplusplus

cout<<"c++";

#else

cout<<"c";

#endif   


##论述含参数的宏与函数的优缺点 

              带参宏  函数

处理时间 编译时 程序运行时

类型参数 没有参数类型问题 定义实参,形参类型

处理过程 不分配内存 分配内存

程序长度 变长 不变

运行速度 不占运行时间 调用和返回占用时间


##用两个栈实现一个队列功能?

思路:

  假设两个栈 A 和B,且都为空。
  可以认为栈 A 为提供入队列的功能,栈 B 提供出队列的功能。
  入队列: 入栈 A 
  出队列:
  1 如果栈B 不为空,直接弹出栈 B 的数据。
  2 如果栈 B 为空,则依次弹出栈 A 的数据,放入栈 B 中,再弹出栈 B 的数据。



##A.c和B.c 两个文件中使用了两个相同名字的static变量,编译的时候会不会有问题?

这两个static 变量会保存到哪里?


static 的全局变量,表明这个变量仅在本模块中有意义,不会影响其他模块。

他们都放在数据区,但是编译器对他们的命名是不同的。

如果要使其他模块也有意义的话,需要使用extern关键字。


##一个单向链表,不知道头结点,一个指针指向其中的一个节点,问如何删除这个指针所指的节点?


将这个指针指向的next节点值copy到本节点,将next指向next->next,并随后删除原next指向的节点。


##阅读代码 找错

void foo(void)

{

unsigned int a=6;

int b=-20;

(a+b>6)?puts(">6"):puts("<=6");

}


当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型。因此,-20变成了一个非常大的正整数

所以该表达式的计算结果大于6.


##

unsigned int zero=0;

unsigned int compzero=0xFFFF; //wrong should be     unsigned int compzero=~0;


##a+++b     //a++  +b





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值