杂碎知识点(二)

本博客内容:
一、程序输出
二、模板
三、memcpy和memmove的区别是什么?
四、交换2个变量的操作
五 、大端字节和小端字节
六、编译器和解释器的区别?
七、空类以及虚函数类的大小
八、memset用法
九、fprintf函数
十、fflush函数使用方法
十一、编写一个日志模块
十二、char * 和char []
十三、指针的运算
十四、C与C++结构体的异同
十五、析构函数可以是virtual,构造函数不能,为什么不同?
十六、既然虚函数是有效的,可以把每个函数都声明为虚函数吗?
十七、编写string类的构造函数、析构函数、拷贝构造函数,赋值函数
十八、请描述模板类的友元重载
十九、堆和栈的比较
二十、字符串拷贝函数strcpy
其他

一、程序输出

1.1

#include<iostream>
#include<stdio.h>
using namespace std;
void func(int a,int b)
{
    printf("\nFunc:a=%d,b=%d",a,b);
}
int main()
{
    int a=5;
    printf("Main:%d,%d",a++,++a);
    func(a,a++);
}

程序的结果取决于栈的实现方式,如果计算机按照从右到左的顺序把参数传给栈,结果为
Main:6 7 Func: a=8 b=7
1.2

int a=43;
printf("%d\n",printf("%d",printf("%d",a)));
//打印结果4321 因为printf()函数打印出来的字符个数。

1.3

int a=3,b;
b=sizeof(++a + ++a);
printf(a,b);
//结果:  3,4  sizeof不会把操作数的求值效果带到sizeof之外。因此执行完sizeof之后,//执行期间发生在a上面的运算效果会消失。

二、模板

1.模板函数
举例:

template<typename T>
T const & Max(T const & a,T const & b)
    reutrn a<b?a:b;

2.模板类

template<class type>
class Stack {
private:
vector<T>elems;
public:
void push(T const &);
};
//cpp
template<class T>
void Stack<T>::push(T const & elem)
    elems.push_back(elem);

三、memcpy和memmove的区别是什么?

即使源区域和目标区域重叠,memmove也能正确处理。
memmove的实现:

void * memmoev(void * dest,void const * sou,int size)
{
register char *dptr=dest;  
register char *sptr=sou;
if(dptr<sptr)      //源位于后方
   {
   while(size-->0)
       *dptr++=*sptr++;
    }else {
    dptr+=size;
    sptr+=size;
    while(size-->0)
        *--dptr=*--sptr; //从后往前赋值
        }
}

四、交换2个变量的操作

//法1
a=a+b;
b=a-b;
a=a-b;
//法2
a=a^b;
b=a^b;
a=a^b;
//法3
a=a+b-(b=a);

五 、大端字节和小端字节

小端字节序:权重最小的值存放在低地址。
大端与之相反。
举例:
0x44332211
内存地址 小端字节序
104   44
103   33
102   22
101   11
程序判断

int num=1;
if(*(char *)&num==1){
    printf("\nLittle-Endian\n");}
else
    printf("\nBig-Endian\n");

六、编译器和解释器的区别?

1.前者把高级指令转换成机器语言,后者把高级指令转换成中间形式。
2.编译器必须把整个程序处理完,然后才能开始执行这个程序;解释器翻译一行执行一行。
3.编译器是在执行完编译过程之后才列出错误的,解释器遇到错误,就停止
4.编译器可以创建独立的可执行文件,如果把程序交给解释器执行,每次运行都需要用到解释器。

七、空类以及虚函数类的大小

空类的sizeof为1
虚函数的话为4.

八、memset用法

函数原型:extern void * memset(void * buffer,int c,int count);
buffer:为指针或数组
c是赋给buffer的值
count:是buffer的长度
方便清空一个数组或者一个结构体的值

九、fprintf函数

函数原型:int printf(FILE * stream,const char * format,…)
参数1:输出的位置,stream是数据流输出,stdout是标准输出,改为文件指针的话,就是与printf参数一样的。
举例子:

int i=10;
FILE * stream=fopen("a.txt","w");
fprintf(stream,"%d\n",i);
fclose(steram);

FILE头文件:#include<fstream>

十、fflush函数使用方法

头文件:#include<stdio.h>
原型:int fflush(FILE * stream);
功能:清除一个流,即清楚文件缓冲区,当文件以写方式打开时,将缓冲区内容写入文件。函数fflush用于将缓冲区的内容输出到文件中去。如果在写完文件后调用函数fflush关闭该文件,同样可以达到将缓冲区的内容写到文件中的目的,但是系统开销很大。

十一、编写一个日志模块

//较简单的实现1
//头文件
class RcLogInfo
{
public:
    RcLogInfo(void);
    ~RcLogInfo(void);
public:
    FILE * m_pfLogFile;
    char m_cInfo[255];
    int setLogFile(FILE * pfLogFile);
    int WriteLogInfo(const char * pInfo);
};
//源文件
RcLogInfo::RcLogInfo(void)
{
    m_pfLogFile = NULL;
    memset(m_cInfo,NULL,sizeof(m_cInfo));
}
RcLogInfo::~RcLogInfo(void)
{
    if (NULL != m_pfLogFile)
    {
        fclose(m_pfLogFile);
        m_pfLogFile=NULL;
    }
}
int RcLogInfo::SetLogFile(FILE *pfLogFile)
{
    m_pfLogFile=pfLogFile;    
    return 0;
}
int RcLogInfo::WriteLogInfo(const char *pInfo)
{
    if(NULL != m_pfLogFile)
    {
        fprintf(m_pfLogFile,"%s",pInfo);
        fflush(m_pfLogFile);
        return 0;
    }
    return 1;
}

十二、char * 和char []

1.
char c[]="hello world";   //分配一个局部数组  存放在内存中的栈
c[0]='t'; //true
2.
char *c="hello world";    //分配一个全局数组       内存中的全局区域
*c='t';//false

十三、指针的运算

#include<iostream>
using namespace std;
int main()
{
    int a[]={1,2,3,4,5};
    int * ptr=(int *)(&a+1);//指向a数组的第6个元素
    cout<<*(a+1)<<endl;                 2
    cout<<*(ptr-1)<<endl;               5
    return 0;
}
//注意:数组名本身就是指针,再加上&,就变成了双指针,就是指二维数组,加1,就是数组整体加上一行。
//几种类型的指针

十四、C与C++结构体的异同

 C语言中的结构体和C++中的结构体以及C++中类的区别
C中的结构体和C++中结构体的不同之处:C中的结构体只能自定义数据类型,结构体中不允许有函数,而C++中的结构体可以加入成员函数。
  C++中的结构体和类的异同:
1.相同之处:都可以包含函数,也可以定义public、private等数据成员。定义了结构体之后,可以用结构体名来创建对象,但C中的结构体不允许有函数;C++中,结构体中可以有成员变量,可以有成员函数,可以从别的类继承,也可以被别的类继承,可以有虚函数。
2.不同之处:结构体定义中的默认情况下是public的,而类中定义的默认是private的,类中的非static成员函数有this指针,类的关键字class能作为template模板的关键字,即template class A; 而struct不可以。

实际上,C中的结构体值涉及到数据结构,而不涉及到算法,就是说在C中数据结构和算法是分离的,而到C++中一个类或者一个结构体可以包含函数。
C语言中结构体中不允许为变量直接初始化,但是C++中可以。
C语言的结构体,sizeof结果为0 C++中结构体,sizeof结果为1

十五、析构函数可以是virtual,构造函数不能,为什么不同?

虚函数采用一种虚调用的办法。虚调用是一种可以在只有部分信息的情况下工作的机制,特别允许我们调用一个只知道接口而不知道其准确对象类型的函数,如果要创建一个对象,势必要知道对象的准确类型,因此构造函数不能为虚。

十六、既然虚函数是有效的,可以把每个函数都声明为虚函数吗?

不行,因为虚函数是有代价的,由于每个虚函数的对象都必须维护一个v表,因此在使用虚函数的时候都会产生一个系统开销,如果仅是一个很小的类,且不想派生其他类,根本没有必要设置为虚函数。

十七、编写string类的构造函数、析构函数、拷贝构造函数,赋值函数

class String
{
public:
 String(const char *str=NULL);
 ~String(void);
 String(const String & other);
 String &  operator =(const String & other);
private:
 char * m_data;
}
String::String(const char * str==NULL)
{
 if(str==NULL)
 {
  m_data=new char[1];
  *m_data='\0';
 }
 else
 {
  int length=strlen(str);
  m_data=new char[length+1];
  strcpy(m_data,str);
 }
 }
 String::~String(void)
 {
   delete m_data;
 }
 String::String(const String & other)
 {
  int length=strlen(other.m_data);
  m_data=new char[length+1];
  strcpy(m_data,other.m_data);
 }
 String& String::operator=(const String& other)
 {
  if(this==&other)
   return *this;
  delete m_data;//或者使用delete [] m_data;
  int length=strlen(oter.m_data);
  m_data=new char[length+1];
  strcpy(m_data,other.m_data);
  return *this;
 }

十八、请描述模板类的友元重载

#include<iostream>
using namespace std;
 template<class T>
   class Test;
 template<class T>
    ostream & operator<<(ostream & out,const Test<T>&obj);
 template<class T>
    class Test
    {
     private:
      int num;
     public:
      Test(int n=0) {num=n;}
      Test(const Test<T>&copy){ num=copy.num;}
      friend ostream & operator<<  <>(ostream & out,const Test<T>&obj);
    };
template<class T>
ostream & operator<<(ostream & out,const Test<T>&obj)
{
   cout<<obj.num;
   return out;
}
int main()
{
 Test<int>t(2);
 cout<<t;
 return 0;
}

十九、堆和栈的比较

1.申请方式

自动分配
coder

2.申请后系统的反应

栈:只要系统剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:首先应该知道OS有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间>所申请空间的堆节点,然后将该节点从空闲节点链表中删除,并将该节点的空间分配给程序。对于大多数系统,会在这块内存空间的首地址记录本次分配的大小,这样,代码中的delete语句才能正确地释放本内存空间。由于找到的堆节点的大小不一定正好等于申请的大小,系统会自动将多余的那部分重新放入空闲链表中。

3.申请大小的限制

栈:是向低地址扩展的数据结构,是一块连续的内存的区域。(意思是:栈顶的地址和最大容量是系统预先规定好的,windows下,栈的大小是2MB,有的是1MB。)总之是一个编译期就确定的常数。如申请空间超过栈的剩余空间,就报栈溢出。
堆:向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表存储空间内存地址的,自然是不连续的。而链表的遍历方向是由低地址向高地址的。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

4.申请效率的比较

栈:系统自动分配,速度较快,但程序员无法控制
堆:由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来方便。另外,在windows中,最好的方式是使用VirtualAlloc分配内存。不是在堆也不在栈,而是直接在进程的地址空间中保留一块内存。

5.堆和栈的存储内容

栈:函数调用时,第一个进栈的是主函数中的下一条指令(函数调用语句的下一条可执行语句的)地址,然后是函数的各个参数,大多数C编译器中,参数是从右往左入栈的,然后是函数中的局部变量,注意静态变量是不入栈的。
堆:一般是在堆的头部用一个字节存放堆的大小。

6.存取效率的比较

char s1[]=”jflajfldjl”: 运行时刻赋值的,栈上的额数组比指针指向的字符串快
char * s2=”fjdlfjld”; 编译时确定的

二十、字符串拷贝函数strcpy

char * strcpy(char * strDest,const char * strSrc)
{
 assert((strDest!=NULL)&&(strSrc!=NULL);
 char * address=strDest;
 while((*strDest++=*strSrc++)!='\0)
     NULL;
    return address;
}

其他

1.C默认const是外部连接的,C++中默认const是内部连接的。
2.静态变量是存放在全局数据区的,而sizeof计算的是栈中分配的大小。

1char *ss="122334";
sizeof(ss)  结果为4,因为是指针
*ss  代表的是第一个字符12char ss[]="122334";
sizeof(ss)  结果为7,要加上/0
*ss  代表的是第一个字符1
strlen的参数只能是char* ,且必须是'\0'结尾的
sizeof()括号中的内容是不执行的。
举例:
a=6;
sizeof(a=8);
执行完上句,a的值仍然为6
//////////////////////
对函数使用sizeof,在编译阶段会被函数的返回值的类型所取代。
//////////////////////
int i=1;
int main()
{
int i=i; }
上述main函数中的i是未定义的值。

字符数组并不要求最后一个字符为'\0',是否需要加入'\0',由系统决定
字符数组和字符串的最明显的区别是:字符串会被默认加上结束符'\0'
但是字符数组的初始化要求最后一个字符必须是'\0';


注意:
  3.printf函数输出先后顺序:
例如:printf(“%d%d\n”,a,b); 先计算出b,再计算出a,接着输出a,然后输出b
  4.找出2个数中比较大的一个
int max=((a+b)+abs(a-b))/2
  5.类的成员函数尾部是否const也能构成重载
  6.重载只是一种语言特性,与多态无关,与面向对象也无关。
  7.关于继承;非公有的派生类不能做基类能做的所有事。在公开场合不能使用基类的成员。
①公有继承:
基类的私有成员仍然是私有的,派生类不可访问基类中的私有成员。
基类成员对派生类对象的可见性对派生类对象来说,基类的公有成员是可见的,其他成员是不可见的。
②私有继承:
公有和保护变为私有,基类的私有不可访问。
基类成员对派生类的对象的可见性对派生类对象来说,基类的所有成员都是不可见的。
③保护继承
公有和保护都变为保护。
基类成员对派生类的对象的可见性对派生类对象来说,基类的所有成员都是不可见的。

#include<iostream>
#include<stdio.h>
using namespace std;
class Animal
{
public :
    Animal(){}
    void eat(){cout<<"eat.\n";}
};
class B:private Animal
{
public:
    B(){}
    void f(){cout<<"fdjl\n";}
    void take(){ eat();}
};
void Func(B & an)
{
    an.take();
}
int main()
{
    B gir;
    gir.eat();  //该行编译不通过,不能直接调用基类的函数
    gir.f();
    Func(gir);
    return 0;
}

8.C++中如果未指定是什么继承,默认是private继承

猜你喜欢

转载自blog.csdn.net/xiongluo0628/article/details/81709311