笔试就是考试,所以以做题和总结来查缺补漏;
1.i++与++i
# a=i++----> a=i ; i=i+1;
# !i++---------> !i ; i=i+1;
# a=++i------>i=i+1 ; a=i;
# !++i-------->i=i+1 ; !i;
对于含有i++的式子,都是先参与运算,再自增;
2.函数参数压栈顺序:从右到左 or 从左到右
3.浮点数和整数在内存中的存储方式不同
float a=125.5的存储方式:
125.5的二进制表示为1111101.1,规定尾数的整数部分恒为1,则表示为1.1111011*2^6;
阶码=6+127=133表示为10000101;
尾数将整数部分1去掉,为1111011;
符号位 阶码 尾数
1 8 23 共32位
125.5在内存中存储方式:0 | 10000101 |111 1011 0000 0000 0000 0000
float a = 1.0f;
cout << (int)a << endl; //强制截取
cout << (int&)a << endl; //float类型(IEEE)的存储方式;int类型的解读
输出结果:
1
1065353216
浮点数0.0f的存储比较特殊
+0.0f ----> 0 00000000 00000000000000000000000
-0.0f ----> 1 00000000 00000000000000000000000
4.malloc/free和new/delete的区别:
malloc/free是c/c++语言的标准库函数
new/delete是c++语言的运算符
非内部数据类型在创建时要自动执行构造函数,消亡时自动执行析构函数,malloc/free无法满足;
Obj* obj = (Obj*)malloc(sizeof(Obj));
free(obj);
malloc()函数只是分配一块内存,而不是生成一个对象,它返回了一个void*类型指针;没有对指针对象进行初始化操作;
free被调用说明:编译器释放这块内存,意思是,可以将这块内存分配给其他数据使用;虽然该指针仍然指向这块内存,但是一定不要再使用,可以令*obj=0改为空指针
Obj* obj=new Obj; //默认初始化
Obj* obj=new Obj();//值初始化
delete obj;
new函数实现了两步,第一步调用malloc分配一块内存;第二步是对指针对象进行初始化操作
new完成初始化操作时,可以采用不同的方式
delete首先完成free功能释放内存,然后调用析构函数
常见问题:#判断内存分配是否成功 #指针未初始化,而使用了空指针
5.
string a="1233";
cout<<a<<endl; //如果包含的头文件是#include<string>
cout<<a.c_str<<endl; #如果包含的头文件是#include<string.h>
6.隐式类型提升、截取、转换
#类型总是提升为较宽的类型
#小于整型的类型在算术表达式计算之前会提升为整型
char char_a='a';
char char_d='b';
int int_b=3;
double dou_c=2.1;
char_a+int_b; //'a'被提升为int类型:97
char_a+char_d; //提升为int型,在运算
int_b+dou_c ; //3被提升为double类型:3.0
int* pt=0; //0被转换为int*类型的空指针
int_b=dou_c; //2.1被截取为int型:2
7.int类型转为(void*)类型
(void *)是一个指针类型;空指针。既然是指针,他们它就是一个地址,在内存中,地址就可以用int来表示嘛;
参数传递中常常用到(void *)的,尤其多线程。
你可以把任何的结构体的地址转为(void *)类型来传递,用到的时候再把它转回来。(好处要到你用到的时候才能体会到了)
8.关于extern "C"
//标准头文件格式
#ifndef _INCvxNANA
#define _INCvxNANA //宏定义防止该头文件被重复引用
#ifdef _cplusplus
extern "C"{
#endif
int a;
double func(int t,int s);
#ifdef _cplusplus
}
#endif
#endif
被extern "C“ 修饰的变量和函数是按照C语言方式编译和连接的,所以extern"C"声明的目的是为了实现C/C++语言的混合编程。
1.在C++中引用C语言中的函数和变量时,就要在其函数前加上extern “C",说明该函数是按照C语言方式编译,连接。
2.C++调用C语言编写的dll时,当包括DLL头文件的接口函数时,加extern "C”
3.在C中调用C++编写的dll时,dll的导出函数必须 加上extern “C"
9.C/C++/MATLAB/.NET各自的特点
#C语言
是一种结构化语言,C程序的设计首先考虑的是如何通过一个过程,对输入进行运算处理得到输出。
#C++
首先考虑的是如何构造一个对象模型,让这个模型更能够契合问题域,通过获取对象的状态信息得到输出。
#matlab
如果涉及向量或矩阵运算,可以使用MATLAB编写组件(COM);
#.NET
大规模的用户界面开发;同COM之间的操作十分容易;对数据访问支持也良好;
10.C/C++中的const
const int t;
const int size=10;
char buf[size];
//C
C中const的意思是:一个一旦初始化就不能被改变的变量;
既然是变量,编译阶段编译器不会知道其值;
//C++
C++中const的意思是:一个必须被初始化的常量;
既然是常量,编译阶段就知道其值;
//C++中const、define在定义常量比较
const有数据类型,define没有;编译器会对前者类型检查,define只是简单的字符替换
11.C++中const使用
//const成员变量
int a=5; //a是变量
int const *b=&a; //*b是常量
int* const b=&a; //b是常量
const int *b=&a; //*b是常量
const int* const b=&a; //*b是常量 b是常量
//const成员函数——"只读函数"
void fun(int a,int b) const{ }
不能改变数据成员的值;
不能调用非const成员函数;
12.指针和数组与"双引号中的字符串"
char a[]="12345";
char *b[]="12345";
sizeof(a); //输出:6
sizeof(b); //输出:4 b是一个指针类型,占4字节
#双引号字符串
编译器在字符串后自动加上空字符'\0'的额外存储片,标志字符串结束
13.内存中数据对齐
#为什么要进行数据对齐
主存储器结构包括存储单元和存储字长;存储容量=存储单元个数*存储字长;
每次内存主存要经过一系列步骤:MAR->译码->发出读或写命令->MDR,这是一个固定开销;
为了节省读写内存的开销,数据存入内存地址必须是该数据长度的整数倍,即数据对齐;
struct {
short a1;
short a2;
short a3;
}A;
struct {
long b1;
short b2;
}B;
struct {
static int a;
int b;
}C;
sizeof(A); // 6
sizeof(B); // 8
sizeof(C); // 4 sizeof计算的是栈中分配的大小;static变量放在全局数据区;
short类型2字节;long类型4字节;在给结构体分配字节大小时,结构体每个数据都要保证数据对齐;
结构体A:
0000 a1;
0002 a2;
0004 a3;
结构体B:
0000 b1;
0004 b2;
在这里虽然b1,b2都确保了数据对齐;但是当定义了一个struct B test[2];其内存地址如下:
0000 test[0].b1;
0004 test[0].b2;
0006 test[1].b1;
000A test[1].b2;
000C test[2].b1;
000F test[2].b2;
则0006不是4的倍数;所以为了保证数据对齐,分配给struct B结构体大小为8字节;
0000 test[0].b1;
0004 test[0].b2;
0008 test[1].b1;
000C test[1].b2;
14.strlen和sizeof的区别
//strlen函数只能接收char*类型参数,且必须以'\0'结束
char *a="123";
cout<<strlen(a) ; //3
char b[]="123";
cout<<strlen(b); //3
char c[]={'1','2','3','\0'};
cout<<strlen(c); //3 ,如果不加'\0'则error
//sizeof是宏定义,只和类型在内存中占得字节数有关
int a[100];
sizeof(a); //100
int *b="123";
sizeof(b); //4
15.关于类在内存中占的空间大小
//空类
class A{ }
class B1{ void fun();}
class B2{ virtual void func(){}}
class C:public A{}
class D:public B1{}
class E:public B2{}
//sizeof(A) 1
//sizeof(B1) 1
//sizeof(B2) 4
//sizeof(C) 1
//sizeof(D) 1
//sizeof(E) 4
#A
空类的size=1;C++要求每个实例在内存中都有独一无二的地址;所以当定义A a;对象a是根据A的大小分配内存,a至少有一个地址;
#B1
类所占内存的大小不包括成员函数大小,出虚拟成员函数除外;
ps:那么类如何访问自己的成员函数捏?
#B2
C++类中有一个指向虚函数的指针,占4字节;无论多少个虚函数,只有这一个指针;
16.指针和引用差别
#引用必须初始化; 指针可以不初始化,但使用前进行NULL检查;
#引用初始化后不能改变; 指针可以改变所指对象;
int *a;
*a=5;
上述代码是错误的;a并没有被初始化;
a没有指向任何地址,*a=5显然是不合理的;
int *a=NULL;表示a指向了地址为0的内存,也就是此处不可解引用,可用于在使用前进行指针检查;
17.函数参数传递
//传值
void func(int a,int &b,int *c)
{
a++;
b++;
(*c)++;
}
void main()
{
int x=1,y=1,z=1;
func(x,y,&z);
cout<<x<<endl; 1 //传值,a的值改变,但x的值未变
cout<<y<<endl; 2 //传引用,y和b指向同一个地址
cout<<Z<<endl; 2 //传地址,改变的同一个地址的值
}
18.函数参数传指针,动态内存
//这是一个错误的程序!!!
void getMemory(char *a,int n)
{
a=(char *)memset(sizeof(char)*n);
}
void main()
{
char *str=NULL;
getMemory(str,100); //函数为指针a分配内存,而不是str,str依然是空;且函数未释放内存(堆),会造成内存泄露
strcpy(str,"hello,nana");
}
//修改为正确程序
char* getMemory(char *a,int n)
{
a=(char *)memset(sizeof(char)*n); //memset在堆上分配内存;
return a;
}
19.字符串常量究竟在哪里分配内存
char* test_func()
{
char s1[]="hello,nana"; //局部,在栈上分配内存,函数结束就释放掉;可修改s[i]的值
char *s2="hello,nana"; //全局,在堆上分配在只读数据段;只读也就是不能修改~~~
}
20.强制类类型转换
class A{
public:
A(){m_a=1,m_b=2;}
~A(){};
void func(){cout<<m_a<<endl;cout<<m_b<<endl;}
private:
int m_a;
int m_b;
};
class B{
public:
B(){m_c=3;}
~B(){};
void func(){cout<<m_c<<endl;
private:
int m_c;
};
int main()
{
A ss; //首先这里创建类对象未用new,则默认会调用类的默认构造函数
ss.func();
B *b=(B*)(&a);
b->func(); // 内存偏移问题;输出 m_a的值1
}
21.区分数组or指针
/*区分定义的是数组还是指针
**数组——这数组元素是什么类型
**指针——指针指向什么类型
*/
float (**def)[10];
//def是二维指针,最终指向float类型的一维数组,size=10
double*(*gh)[10];
//gh是指针,指向double*类型的一维数组size=10
double(*f[10])();
//f是数组,数组元素类型时指向函数的指针,函数类型时无参数返回double类型的函数
int (*(*F)(int,int))(int);
//F是函数指针,指向返回值为函数指针,接收两个int参数的指针,返回的函数指针类型为接收int参数返回int类型的函数
int v[2][5]={{1,2,3,4,5},{6,7,8,9,10}};
int (*a)[5]=v;
cout<<**a<<**(a+1)<<endl; 1 11
cout<<*(a[0])<<*(a[1])<<endl; 1 11
cout<<*(*a+1)<<endl; 2
/*
**搞清楚a,*a,**a分别是什么类型,上述问题迎刃而解~
#a是指向一维int型数组的指针;所以a+1是指向下一个这种类型的指针
#a[0]=*(a+0); a[1]=*(a+1)
#*a是int型指针;
#**a是int型
*/
22.&a和a
#include<iostream>
using namespace std;
int main()
{
int a[]={1,2,3};
cout<<&(a[0])<<endl; //002FFDCC
cout<<&(a[1])<<endl; //002FFDD0
cout<<&(a[2])<<endl; //002FFDD4
cout<<a<<endl; //002FFDCC
cout<<a+1<<endl; //002FFDD0
cout<<&a<<endl; //002FFDCC
cout<<&a+1<<endl; //002FFDC8 //&a+1和a+1的区别
getchar();
return 0;
}