可以在一个函数的内部直接为另一个函数的进行声明。
指针数组与数组指针的区别方法:
1、 float (**def)[10];def是一个二级指针, 它指向是一个一维数组的指针,数组的元素都是float 2、 double *(*gh)[10];gh是一个指针,它指向一个一维数组,数组的元素都是double*。
3、 double (*f[10])();f是一个数组,f有10个元素,元素都是函数的指针,指向的函数类型是没有参
数并且返回double的函数。
4、 int *((*b)[10]); == int *(*b)[10];是一维数组的指针。
5、 int (*(*ff)(int ,int ))(int);ff是一个函数的指针,指向的函数的类型是有两个int参数并且返
回一个函数指针的函数,返回的函数指针指向有个int参数并且返回int的函数。
char *strA() {
char str[] = “Hello, world!”;
return str;//str为局部变量,函数调用结束后就会被收回。
int (*p)[10]//为指针,数组指针:类型为int,的数组指针,指针p指向的地址为数组的地址。 int *p[10];//为数组,指针数组:p是一个维数为10的数组,数组中存有的内容为指针类型的
}//这样做是无法获取到str的值来使用它的,可以参考以下的例子进行修改: const char * strA() { }
int *temp; *temp = *p;这是一段不符合逻辑的代码,int *temp新建了一个指针(但没有分配内存)。*temp = *p不是指向而是拷贝。把*p所指向的内存里的值(也就是实参a的值)拷贝到*temp所指向内存里了。但是int *temp不是不分配内存吗?的确不分配,于是系统在拷贝时临时给了一个随机地址,让它存值。分配的随机地址是个“意外“,并且函数结束后不回收,造成内存泄露。
void swap(int *a, int *b) {
int *temp; temp = p; p = q; q = temp;
static char str[] = “Hello, world!”;//使用静态变量来存储,即使函数结束后该变量也没有销return str; 毁。
}//这是无法真正更改a与b的值,只是在函数中交换了地址,回到主函数后地址又没有改变。 int main(){ int a = 3; int b = 4; swap(&a, &b);} class A
{};//sizeof(A) == 1 class B : public A {};//sizeof(B) == 1; class C : public virtual B {};//sizeof(C) == 4;
这说明了空类所占的空间为1,单一继承的空类空间也为1,多重继承的空类空间还是1,但是虚继承涉及到虚表(虚指针),所以sizeof(C)的大小为4.
char var[100]; int text(char var[]) { }
int **a[3][4];//存着指向int *a[3][4]的一个指针,所以计算sizeof(a) == 3 * 4 *4 = 48;
sizeof的问题:
1. sizeof不是函数,也不是一元运算符,它是一个类似宏定义的特别的关键字,括号内的内容在编译过
程中是不被编译的,而是被替换类型,如int a = 8; sizeof(a)。在编译过程中,不管a的值是什么,只是被替换成类型sizeof(int),结果为。如果sizeof(a = 6)呢?也是一样换成a的类型。但是要注意,因为a=6是不被编译的,所以执行完sizeof(a = 6)后,a的值还是8,是不变的。
2. unsigned影响的是最高位bit的意义,数据长度是不会被改变的,sizeof(unsigned int) ==
sizeof(int)
3. 自定义类型的sizeof取值等同于它的类型原型。如: typedef short WORD;
sizeof(short)==sizeof(WORD);
4. 对函数使用sizeof,在编译阶段会被函数返回值的类型取代。
sizeof和strlen之间的区别:
1. char* ss = “0123456789”;sizeof(ss)结果为4,ss是指向字符串常量的字符指针。sizeof(*s)结
果为1,*ss是第一个字符。
2. char ss[] = “0123456789”;结果是11,ss是数组,计算到”\\0”位置,因此是(10 + 1)。sizeof(*s)
结果为1,*ss是第一个字符。
3. char ss[100] = “0123456789”;ss表示在内存中预分配的大小。strlen结果为10,它的内部实现
是用一个循环计算字符串的长度,直到”\\0”为止。
4. int ss[100] = “0123456789”;sizeof(ss)结果为400,ss表示在内存中的大小。strlen(ss)是错误,
return sizeof(var);//4,因为var[]等价于*var,已经退化成一个指针。
strlen的参数只能是char*,并且必须是以”\\0”结尾的。
5. class X{int i; int j; char k;}; X x; sizeof(X) == sizeof(x) == 12;内存补齐。 class AA {
int a; static int b;
};//sizeof(A) == 4
因为静态变量是存放在全局数据区,而sizeof计算栈中分配的大小,是不会将b变量计算在内的。
class A {
bool m_bTemp; int m_nTemp; bool m_b;
};// sizeof(A) = 12; class B {
当结构体内的类型长度最大的元素的长度都小于处理器的位数的时候,便以结构体里面最长的数据元素为对齐单位,也就是说,结构体的长度一定是最长的数据元素的整数倍。如果结构体内存在长度大于处理器位数的元素,那么就以处理器的位数为对齐单位。但是结构体内类型相同的连续元素将在连续的空间内,和数组一样。
const与#define相比有什么不同?
前者比后者有更多的优点,const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换中可能会产生意料不到的错误。有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。
在类中的数据成员加上mutable后,修饰为const的成员函数,就可以修改它了。
用一个宏定义FIND求一个结构体struc里某个变量相对struc的偏移量。 struct {int a; char b[20]; double ccc;}struc; FIND(student, a);//等于0
方法:#define FIND(struc, e) (size_t)&(((struc*)0)->e)//其中(struc*)0表示将常量0强制转化为struc*性指针所指向的地址;&(((struc*)0)->e)表示取结构体指针(struc*)0的成员e的地址,因为该结
int m_nTemp; bool m_bTemp; bool m_b;
};// sizeof(B) = 8;
构体的首地址为0,所以其实就是得到了成员e距离结构体首地址的偏移量,(size_t)是一种数据类型,为了便于不同系统之间移植,最好定义为一种无符号型数据,一般为unsigned int。
#define SECONDS (60 * 60 *24 *365)UL//用来表示一年中有多少秒,表达式中用到UL(表示无符号长整型),是一个很好的方法。
int max = ((a + b) + abs(a - b))/2;//有两个变量a和b,不用“if”、“?”、”switch”或其他判断语句,找出两个数中间比较大的。
float a = 1.0f; cout< int(&)a相当于将该浮点数地址开始的sizeof(int)个字节当成int型的数据输出。 一、预备知识—程序的内存分配 一个由c/C++编译的程序占用的内存分为以下几个部分 1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。 2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。 3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放 4、文字常量区—常量字符串就是放在这里的。 程序结束后由系统释放 5、程序代码区—存放函数体的二进制代码。 二、例子程序 这是一个前辈写的,非常详细 //main.cpp int a = 0; 全局初始化区 char *p1; 全局未初始化区 main() { int b; 栈 char s[] = \栈 char *p2; 栈 char *p3 = \在常量区,p3在栈上。 static int c =0; 全局(静态)初始化区 p1 = (char *)malloc(10); p2 = (char *)malloc(20); 分配得来得10和20字节的区域就在堆区。 strcpy(p1, \放在常量区,编译器可能会将它与p3所指向的\优化成一个地方。 } 二、堆和栈的理论知识 2.1申请方式 stack: 由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间 heap: 需要程序员自己申请,并指明大小,在c中malloc函数 如p1 = (char *)malloc(10); 在C++中用new运算符 如p2 = (char *)malloc(10); 但是注意p1、p2本身是在栈中的。 2.2 申请后系统的响应 栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。 堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时, 会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。 2.3申请大小的限制 栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。 堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。 2.4申请效率的比较: 栈由系统自动分配,速度较快。但程序员是无法控制的。 堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便. 另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。 2.5堆和栈中的存储内容 栈: 在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。 当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条