c++八股文整理(一)

1. a和&a有什么区别?

#include "stdio.h"
int main()
{
 int a[5] = { 1,2,3,4,5 };
 int *ptr = (int *)(&a + 1);
 printf("%d,%d", *(a + 1), *(ptr - 1));
 return 0;
}
​
  • a 在这里代表是的数组首元素的地址即 a[0]的首地址,其值为 0x005efda0。
  • &a 代表的是数组的首地址,其值为 0x005efda0。
  • a与&a值相同,代表的含义不同
  • a+1 的值是 0x005efda0+1*sizeof(int),等于 0x005efda4。
  • &a+1 的值是(0x005efda0 +(sizeof(a)= 5*sizeof(int))= 0x005efdb4 {0xcccccccc, 0xcb626a90, 0x005efdd0, 0x0029200e, 0x00000001}

2.区别以下指针类型?

int *p[10];
int (*p)[10];
int *p(int);
int (*p)(int);
  • int *p[10]表示指针数组,强调数组概念,是一个数组,数组大小为10,数组内每个元素都是指向int类型的指针变量。
  • int (*p)[10]表示数组指针,强调是指针只有一个变量,是指针类型,不过指向的是一个int类型的数组,这个数组大小是10。
  • int *p(int)是函数声明,函数名是p,参数是int类型的,返回值是int *类型的。
  • int (*p)(int)是函数指针,强调是指针,该指针指向的函数具有int类型参数,并且返回值是int类型的

3. 常量指针和指针常量区别?(有待看书确认,primer p56)

  • 常量指针定义:又叫常指针(常量的指针),即这是个指向常量的指针,说明指针的值(地址)是常量,而不是地址指向的值。可以写作int const *p或const int *p
  • 指针常量定义:指针是个常量,必须初始化,一旦初始化完成,它的值(也就是存放在指针中的地址)就不能在改变了,即不能中途改变指向,如int *const p

4.strlen和sizeof区别?

  • sizeof 是运算符,结果在编译时获。参数可以是任何数据的类型或者数据。
  • strlen 是函数,结果在运行时获得。参数只能是字符指针且结尾是'\0'的字符串。
  • sizeof指针得到的是本指针的大小,sizeof引用得到的是引用所指向变量的大小。
int main(int argc, char const *argv[]){
      
      //ziseof 会把从主函数中传进来的字符数组当作是指针来处理。指针的大小又是由机器来决定,而不是人为的来决定的。
      const char* str = "name";
      sizeof(str); // 取的是指针str的长度,64位计算机下 是8。
      strlen(str); // 取的是这个字符串的长度,不包含结尾的 \0。大小是4

      //--------------------------------------------------------
      char str[] = "Hello World";
      char str1[100] = "Hello World";
 
      cout << strlen(str) << endl; //10。测量的是字符的实际长度,以'\0'结束 且不包含'\0' 
      cout << sizeof(str) << endl; //11。测量的是字符的分配大小,如果未分配大小,则遇到'\0' 结束(包含'\0' ,也就是strlen测量的长度加1)
      cout << sizeof(str1) << endl; //100。如果已经分配内存大小,返回的就是分配的内存大小。
      return 0;
  }

5.变量声明和定义区别?

  • 定义 = 声明  +  初始化(就是给一个值)
  • 声明仅仅是把变量的声明的位置及类型提供给编译器,并不分配内存空间;
  • 定义要在定义的地方为其分配存储空间
  • 相同变量可以在多处声明(外部变量extern),但只能在一处定义。
  • extern声明不是定义,不分配存储空间。extern告诉编译器变量在其他地方定义了。
  • 例如:extern int i; //声明,不是定义 ;   int i; //声明,也是定义              

6.宏定义和typedef区别?

  • 宏 主要用于定义常量及书写复杂的内容;typedef主要用于定义类型别名
  • 宏 替换发生在编译之前,在预处理阶段完成替换,之后被替换的文本参与编译,属于文本插入替换;typedef是编译的一部分。
  • 宏 不是语句,不在在最后加分号;typedef是语句,要加分号标识结束。
  • 示例1:   先定义: typedef char* PSTR;

  •               然后:    int mystrcmp(const PSTR, const PSTR);

  •      const PSTR 实际上相当于const char*吗?不是的,它实际上相当于char* const。

            原因在于const给予了整个指针本身以常量性,也就是形成了常量指针char* const。

            简单来说,记住当const和typedef一起出现时,typedef不会是简单的字符串替换。

  •  示例2:   下述两者效果不同

    •        typedef    (int*)      pINT;    // pINT a,b;的效果同int *a; int *b;表示定义了两个整型指针变量。typedef具有一定的封装性

      • #define    pINT2    int*       //pINT2 a,b;的效果同int *a, b;表示定义了一个整型指针变量a和整型变量b。

7.既然有了malloc/free,C++中为什么还需要new/delete呢?直接用malloc/free不好吗?

  • 在对非基本数据类型的对象使用的时候,对象创建的时候还需要执行构造函数,销毁的时候要执行析构函数。而malloc/free是库函数,是已经编译的代码,所以不能把构造函数和析构函数的功能强加给malloc/free,所以new/delete是必不可少的。
  • malloc仅仅分配内存空间,free仅仅回收空间,不具备调用构造函数和析构函数功能,用malloc分配空间存储类的对象存在风险;new和delete除了分配回收功能外,还会调用构造函数和析构函数。
  • new: 1.调用名为operator new的标准库函数分配足够空间,2.调用相关对象的构造函数,返回指向构造后的对象的指针
  • delete:1.对指针所指对象运行析构函数;2. 调用名为operator delete的标准库函数释放该对象所用内存
  • malloc和free是标准库函数,支持覆盖; new和delete是运算符,支持重载。
  • new是封装了malloc,直接free不会报错,但是这只是释放内存,而不会析构对象。 

8.你觉得堆快一点还是栈快一点?

  • 栈由系统分配,速度快,不会有碎片,是一块连续的内存区域,大小是操作系统预定好的. 一般默认是4M。栈有静态分配和动态分配,静态分配由编译器完成(如局部变量分配),动态分配由alloc函数分配,但栈的动态分配的资源由编译器进行释放,无需程序员实现。
  • 堆由程序员分配,速度慢,且会有碎片,是不连续的内存区域(因为系统是用链表来存储空闲内存地址,自然不是连续的),堆大小受限于计算机系统中有效的虚拟内存,一般是 1G - 4G。堆都是动态分配。 ​​​​​​​

9.指针和引用的区别

  • 指针是一个变量,存储的是一个地址,引用跟原来的变量实质上是同一个东西,是原变量的别名
  • 指针可以有多级,引用只有一级
  • 指针可以为空,引用不能为NULL且在定义时必须初始化 且 在初始化之后不可再改变。
  • 当把指针作为参数进行传递时,也是将实参的一个拷贝传递给形参,两者指向的地址相同,但不是同一个变量,在函数中改变这个变量的指向不影响实参,而引用却可以。
  • 引用本质是一个指针,同样会占4字节内存;指针是具体变量,需要占用存储空间(,具体情况还要具体分析)。
  • 类对象作为参数传递的时候使用引用。需要返回函数内局部变量的内存的时候用指针。使用指针传参需要开辟内存,用完要记得释放指针,不然会内存泄漏。而返回局部变量的引用是没有意义的
void test(int *p)
{
  int a=1;
  p=&a;
  cout<<p<<" "<<*p<<endl;
}

int main(void)
{
    int *p=NULL;
    test(p);
    if(p==NULL)
    cout<<"指针p为NULL"<<endl;
    return 0;
}
//运行结果为:
//0x22ff44 1
//指针p为NULL


void testPTR(int* p) {
	int a = 12;
	p = &a;

}

void testREFF(int& p) {
	int a = 12;
	p = a;

}
void main()
{
	int a = 10;
	int* b = &a;
	testPTR(b);//改变指针指向,但是没改变指针的所指的内容
	cout << a << endl;// 10
	cout << *b << endl;// 10

	a = 10;
	testREFF(a);
	cout << a << endl;//12
}

10.结构体内存对齐问题?

  • 结构体内成员按照声明顺序存储,第一个成员地址和整个结构体地址相同。
  • 未特殊说明时,按结构体中size最大的成员对齐(若有double成员,按8字节对齐。)

11.在main执行之前和之后执行的代码可能是什么?

main函数执行之前,主要就是初始化系统相关资源

  • 设置栈指针
  • 初始化静态static变量和global全局变量,即.data的内容
  • 将未初始化部分的全局变量赋初值:数值型shortintlong等为0boolFALSE,指针为NULL等等,即.bss的内容
  • 全局对象初始化,在main之前调用构造函数,这是可能会执行前的一些代码
  • 参数argcargv等传递main函数,然后才真正运行main函数
  • __attribute__((constructor))

main函数执行之后

  • 全局对象的析构函数会在main函数之后执行;
  • 可以用 atexit 注册一个函数,它会在main 之后执行;
  • __attribute__((destructor))​​​​​​​​​​​​​​

      •   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值