网上知识点汇总一

1、fork函数 http://blog.csdn.net/jason314/article/details/5640969

使用fork函数得到的子进程从父进程的继承了整个进程的地址空间,包括:进程上下文、进程堆栈、内存信息、打开的文件描述符、信号控制设置、进程优先级、进程组号、当前工作目录、根目录、资源限制、控制终端等。子进程与父进程的区别在于:1、父进程设置的锁,子进程不继承(因为如果是排它锁,被继承的话,矛盾了)2、各自的进程ID和父进程ID不同3、子进程的未决告警被清除;4、子进程的未决信号集设置为空集。


2、

class String
{
public:
  String(const char *str = NULL); // 通用构造函数
  String(const String &another);  // 拷贝构造函数
  ~String(); // 析构函数
  String& operater =(const String &rhs); // 赋值函数
private:
  char* m_data; // 用于保存字符串
};

String::String(const char* str)
{
   if ( str == NULL ) // strlen在参数为NULL时会抛异常才会有这步判断
   {
       m_data =new char[1] ;
       m_data[0] ='\0' ;
   }
   else
   {
       m_data =new char[strlen(str) +1];
       strcpy(m_data,str);
   }
} 
String::String(const String &another)
{
    m_data =new char[strlen(another.m_data) +1];
    strcpy(m_data,another.m_data);
}


String& String::operator=(const String &rhs)
{
    if ( this==&rhs)
        return*this ;
    delete []m_data; //删除原来的数据,新开一块内存
    m_data =new char[strlen(rhs.m_data) +1];
    strcpy(m_data,rhs.m_data);
    return*this ;
}


String::~String()
{
    delete []m_data ;
}

3、公有继承

当类的继承方式为公有继承时,基类的公有和保护成员的访问属性在派生类中不变,而基类的私有成员不可访问。即基类的公有成员和保护成员被继承到派生类中仍作为派生类的公有成员和保护成员。派生类的其他成员可以直接访问它们。无论派生类的成员还是派生类的对象都无法访问基类的私有成员。
 
私有继承
当类的继承方式为私有继承时,基类中的公有成员和保护成员都以私有成员身份出现在派生类中,而基类的私有成员在派生类中不可访问。基类的公有成员和保护成员被继承后作为派生类的私有成员,派生类的其他成员可以直接访问它们,但是在类外部通过派生类的对象无法访问。无论是派生类的成员还是通过派生类的对象,都无法访问从基类继承的私有成员。通过多次私有继承后,对于基类的成员都会成为不可访问。因此私有继承比较少用。
 
保护继承
保护继承中,基类的公有成员和私有成员都以保护成员的身份出现在派生类中,而基类的私有成员不可访问。派生类的其他成员可以直接访问从基类继承来的公有和保护成员,但是类外部通过派生类的对象无法访问它们,无论派生类的成员还是派生类的对象,都无法访问基类的私有成员。

4、下面这个程序执行后会有什么错误或者效果:

1
2
3
4
5
6
7
#define MAX  255
int main()
{
     unsigned  char A[MAX], i;
      for (i =  0 ; i <= MAX; i++)
         A[i] = i;
}
死循环加数组越界访问(C/C++不进行数组越界检查)
MAX=255
数组A的下标范围为:0..MAX-1,这是其一..
其二.当i循环到255时,循环内执行:
  A[255]=255;
这句本身没有问题..但是返回for (i=0;i<=MAX;i++)语句时,
由于unsigned char的取值范围在(0..255),i++以后i又为0了..无限循环下去.

5、void类型没有分配内存,而引用必须是另一个固定内存变量的别名,所以不能指向void


6、以下程序段执行后结果是()
1
2
3
4
5
6
7
8
9
10
11
#include<stdio.h>
void main()
{
     short *p,*q;
     short arr[15]={0};
    p=q=arr;
    p++;
     printf ( "%d," ,p-q);
     printf ( "%d," ,( char *)p-( char *)q);
     printf ( "%d" , sizeof (arr)/ sizeof (*arr));
}
指针自增、自减每次移动的偏移量是指针所指向对象的字节大小,所以p++与q的偏移量是2个字节。
指针相减的值是指针地址的偏移除以指针每次移位的大小;
1)p-q=1;偏移量为2个字节,每次移动2个字节,所以为1
2)(char *)p-(char *)q,指针的偏移没变,但是每次指针移位是按照(char*)类型移动,即每次移动1个字节,所以是2
3)数字每次元素2个字节,所以sizeof(arr)为30,sizeof(*arr)为2。

7、
inta[5]={1,2,3,4,5};
int*ptr=(int*)(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));
数组名的值是一个指针常量,也就是数组第一个元素的地址。*(a+1)等同于a[1],*(a+1)=2。
&a+1指向数组最后一个元素的下一个位置,故*(ptr-1)指向数组的最后一个元素。

8、
1
2
3
#define  A(x) x+x
int i=5*A(4)*A(6);
cout<<i;
以上程序输出是多少?
宏定义的A(x)全部替换为x+x,但注意不要加括号!
i=5*4+4*6+6=20+24+6=50

9、关于bool,int,float,指针类型的变量a 与“零”的比较语句

BOOL : if ( !a ) or if(a)

int : if ( a == 0)

float : const EXPRESSION EXP = 0.000001

if ( a < EXP && a >-EXP)

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


10、
1
2
3
4
5
char *p1;int64 *p2;
p1=( char *) 0x800000 ;
p2=(int64 *) 0x800000 ;
char *a=p1+ 2
int64_t *b=p2+ 2
那么a=  1  ,b=  2  
我们定义指针的时候给指针一个类型就是为了方便指针的加减操作。p1是char类型指针,每个char占一个字节,所以p1+2就是在p1的基础上加2个char的长度,就是两个字节。p2是指向64位int型的指针,所以p2+2就是p2加上两个64位int的长度,也就是加上128位,即16个字节。用16进制表示是0x10
所以a=0x800000+0x2=0x800002
a=0x800000+0x10=0x800010

11、以下代码中,A 的构造函数和析构函数分别执行了几次:      

A*pa=new A[10];

delete []pa;

10

12、用C++语法来看,下列的哪个赋值语句是正确的?
char a=12
int a=12.0
int a=12.0f
int a=(int)12.0
A项在赋值为0-127时无警告,但B/C/D均有损失精度的警告,编译还是能通过的。B、C、D项的区别是:B 项的默认为double型转向int型,C项因等号后“12.0f”的  ‘f’使其转换为folate型,D项直接通过在等号的右边加“(int)”强制类型转换,与B项相同的是:是从默认的double型转换为int型。A项会对应的ASCII字符,但在大于127时会发生常量截断会有警告。所以综上,此题A、B、C、D是都正确的

13、dynamic_cast<>用于C++类继承多态间的转换,分为:
1.子类向基类的向上转型(Up Cast)
2.基类向子类的向下转型(Down Cast)
其中向上转型不需要借助任何特殊的方法,只需用将子类的指针或引用赋给基类的指针或引用即可,dynamic_cast向上转型其总是肯定成功的。

而向下转换时要特别注意:dynamic_cast操作符,将基类类型的指针或引用安全的转换为派生类的指针或引用。dynamic_cast将一个基类对象指针(或引用)cast到继承类指针,dynamic_cast会根据基类指针是否真正指向继承类指针来做相应处理。这也是dynamic_cast与其他转换不同的地方,dynamic_cast涉及运行时类别检查,如果绑定到引用或指针的对象不是目标类型的对象,则dynamic_cast失败。如果是指针类型失败,则dynamic_cast的返回结果为0,如果是引用类型的失败,则抛出一个bad_cast错误。
注意:dynamic_cast在将父类cast到子类时,父类必须要有虚函数。因为dynamic_cast运行时需要检查RTTI信息。只有带虚函数的类运行时才会检查RTTI。

14、C++中为什么用模板类的原因
答:(1)可用来创建动态增长和减小的数据结构 (2)它是类型无关的,因此具有很高的可复用性。 (3)它在编译时而不是运行时检查数据类型,保证了类型安全 (4)它是平台无关的,可移植性 (5)可用于基本数据类型

16、
int f() { int *a = new int(3); return *a; }内存泄露,没有delete
int *f() { int a[3] = {1, 2, 3}; return a; }数组是临时的,根本传不到主调函数里
17、
有以下程序段:
1
2
3
4
5
char *p, *q;
p = ( char *)malloc(sizeof( char ) *  20 );
q = p;
scanf(“%s %s”, p, q);
printf(“%s %s\n”, p, q);
若从键盘输入:abc def↙,则输出结果是( )
p q 指向同样的地址, 
scanf("%s %s", p, q);"abc"赋值给p,然后"def"赋值给q(即p),把之前的赋值覆盖了。 

18、定义二维数组,一定要确定列数

19、若有以下定义和语句:
1
2
char s1[]= "12345" ,*s2= "1234" ;
  printf( "%d\n" ,strlen(strcpy(s1,s2)));
则输出结果是
strcpy(s1,s2)这个函数是把s2字符串拷贝到s1这个字符串,同时也把s2的 '\0' 拷过去

1.  字符串最后以  \0  结束。strcpy将'1234\0'复制到目的地址

2.  strlen()遇到  \0  停止


20、

以下关于STL的描述中,____是错的。

正确答案: C   

STL容器是线程不安全的
当容量不够时,vector内部内存扩展方式是翻倍
std::sort是稳定排序
std::bitset不是一个STL容器
std::stack默认是用deque实现的
std::string中可以存储多个’\0’字符
A:“很多程序员希望STL实现是完全线程安全的“。所以不安全。
B:vector的存在可以使开发者不必关心内存的申请和释放。但是,vector的一个缺点就是它的内存分配是按照2的倍数分配内存的。
C:错误。要知道 std::sort 不是稳定的排序算法,它不保证“相等”元素的相对位置,使用 std::stable_sort 来保证这一点
D:STL的容器可以分为以下几个大类: 
一:序列容器, 有vector, list, deque, string.
二 : 关联容器,     有set, multiset, map, mulmap, hash_set, hash_map, hash_multiset, hash_multimap
三: 其他的杂项: stack, queue, valarray, bitset
E:正确。堆栈是一个线性表,插入删除操作都在一端进行,deque是先进先出的,操作原理和stack是一样的

C++STL中常用的容器和类型支持下标"[]"运算
vector:随机访问迭代器,复杂度O(1)
deque:同上,O(1)
map:双向迭代器,不过由于是关联容器,需要通过key访问alue的方法,O(h),h为树的高度
unordered_map:前向迭代器,同上,平摊复杂度O(1),最差O(n),也与散列函数的好坏有关。
string:同vector

21、数组也可以动态实现,用指针创建, 不一定非要有编译时就确定大小

22、
1
time_t t;
哪个选项可以将t初始化为当前程序的运行时间?
clock() 就是该程序从启动到函数调用占用CPU的时间
time( &t );为获取系统时间
localtime(&t);   将一个UTC时间转为本地时间

23、C语言里i=5,j=7,请问i|j等于多少?
| 是位操作符 或 的意思
先把5和7转化为二进制 101 和 111
按位或就是 111 ,所以答案是7
24、

1
2
3
4
5
struct Node
{
    int size;
    char data[0];
//编译器会认为这就是一个长度为0的数组,而且会支持对于数组data的越界访问
};
 柔性数组,它只能放在结构体末尾,是
申明一个长度为0的数组,就可以使得这个结构体是可变长的。对于编译器来说,此时长度为0的数组并不占用空间,因为数组名本身不占空间,
它只是一个偏移量, 数组名这个符号本身代 表了一个不可修改的地址常量 (注意:数组名永远都不会是指针! ),但对于这个数组的大小,
我们可以进行动态分配 请仔细理解后半部分,对于编译器而言,数组名仅仅是一个符号,它不会占用任何空间,它在结构体中,只是代表了
一个偏移量,代表一个不可修改的地址常量!
 对于0长数组的这个特点,很容易构造出变成结构体,如缓冲区,数据包等等:
注意:构造缓冲区就是方便管理内存缓冲区,减少内存碎片化,它的作用不是标志结构体结束,而是扩展
柔性数组是C99的扩展,简而言之就是一个在struct结构里的标识占位符(不占结构struct的空间)

25、下面程序的输出结果是
1
2
3
4
5
6
7

#include<iosteam.h>
void  main(){
     int n[][3] = {10,20,30,40,50,60};
     int (*p)[3];
    p=n;
    cout<<p[0][0]<< "," <<*(p[0]+1)<<(*p)[2]<<endl;
}
p[0]表示第一行的地址,p[0]+1表示第一行首地址偏移一个地址,即a[0][1]。
int (*p)[3],p是一个数组指针,指向三个元素为一个数组的指针,(*p)表示第一行,(*p)[2]表示a[0][2]

26、int fseek(FILE *stream, long offset, int fromwhere);函数设置文件指针stream的位置。

如果执行成功,stream将指向以fromwhere为基准,偏移offset(指针偏移量)个字节的位置,函数返回0。

如果执行失败(比如offset超过文件自身大小),则不改变stream指向的位置,函数返回一个非0值。

实验得出,超出文件末尾位置,还是返回0。往回偏移超出首位置,返回-1,且指向一个-1的位置,请小心使用。

fseek函数和lseek函数类似,但lseek返回的是一个off_t数值,而fseek返回的是一个整型。

27、
union类型的变量在定义时是可以被初始化的,定义如下union类型
1
2
3
4
5
6
union Test
{
     int a;
     float b;
};
Test test = { 1 };
test变量的定义可以初始化,初始值的类型必须是union中第一个成员的类型。

28、
 如果一个类中声明了纯虚函数,其派生类中没有对该函数定义,那该函数在派生类中仍为纯虚函数,凡是包含纯虚函数的类都是抽象类。
通常重载函数调用的依据是函数名、参数类型、参数个数。 类的静态成员是属于类的而不是属于哪个对象的,
因此可以说是所有对象所共有的。内联函数是在编译时将目标代码插入的


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值