关于这几个问题论坛上已经有比较详细的文章,这里主要描述一些遇到的问题,并附上链接。
例如采用数组的形式顺序存储线性表时,以下两种表示都可以:
typedef struct LNode *List; struct LNode{ ElementType Data[MAXSIZE]; int Last; }; typedef struct LNode *List; struct LNode{ ElementType *Data; int last; };他们在初始化的时候会略有不同,第一种结构体的内存空间中就包括这个数组,而第二种,结构体内只是一个指针,在初始化线性表时要再给这个指针指向的数组申请内存空间。
List MakeEmptyList(){ List PtrL; PtrL = (List)malloc(sizeof(LNode)); PtrL->Last = -1; return PtrL; } List MakeEmptyList(int MaxSize){ List PtrL; PtrL = (List)malloc(sizeof(LNode)); PtrL->Data = (ElementType *)malloc(MaxSize * sizeof(ElementType)); PtrL->Last = -1; return PtrL; }那这里就有个问题,这两种结构体分别是申请了多大的空间?假设我们这里的ElementType是double型的,对于第一个定义中Maxsize为2。
#include<stdlib.h> #include<iostream> using namespace std; #define MAXSIZE 2 typedef struct LNode *List; struct LNode{ double Data[MAXSIZE]; int Last; }; // typedef struct LNode *List; // struct LNode{ // int *Data; // int last; // }; int main() { cout << sizeof(LNode) << endl; return 0; }输出结果为24,但是明明应该是8+8+4=20啊,为什么是24;而对于第二中定义,输出结果为16,本应该是8+4=12。(在64位系统上的测试,指针为8个字节)这就是因为编译器对结构体分配内存时要进行对齐操作。 关于对齐过程,在这篇博客中非常详细:关于结构体内存对齐总结。看了不少文章都说不到点上。 注意一点:如何尽量减少结构体内存空间的占用呢? 数据类型的排列顺序 24:
typedef struct { double d; double c; int b; char a; }Lenth;32:
typedef struct { double c; int b; double d; char a; }Lenth;上面的例子中用到了申请动态内存空间的函数:
void* malloc(size_t size)void*(无值型)
malloc内存分配成功则是返回void * ,需要通过强制类型转换将void*指针转换成我们需要的类型,开辟成功返回值为这块内存空间的地址,开辟失败返回值为NULL,size为空间的大小,单位为字节。在用malloc开辟空间后要检查是否开辟内存成功,使用完这段内存后要用free(void* ptr)释放内存,否则会造成内存泄漏。 在C++中一般使用new和delete的组合,两者区别在于:new和malloc的区别
1)先从简单数据类型的变量看起,举一个简单的例子,交换两个整型的变量:
#include<stdlib.h> #include<iostream> using namespace std; void exchange(int x, int y){ cout << x <<" "<< &x << endl; cout << y <<" "<< &y << endl; int p = x; x = y; y = p; } void exchangeP(int *x, int *y){ cout << *x <<" "<< x << endl; cout << *y <<" "<< y << endl; int p = *x; *x = *y; *y = p; } int main() { int a = 1, b = 2; int *A = &a; cout << a <<" "<< &a << endl; cout << b <<" "<< &b << endl; cout << endl; exchange(a, b); cout << endl; exchangeP(&a, &b); cout << endl; cout << a <<" "<< &a << endl; cout << b <<" "<< &b << endl; return 0; } 1 0x61fe14 2 0x61fe10 1 0x61fdf0 2 0x61fdf8 1 0x61fe14 2 0x61fe10 2 0x61fe14 1 0x61fe10 [Done] exited with code=0 in 0.352 seconds运行结果一目了然,如果我们把这个整型变量的实参直接传递到函数中,形参在函数中相当于是复制了一份变量(地址不同)去做交换,换完就会被释放,根本不影响实参;所以就要通过指针的方式传递,这样操作的就是指针指向的地址(实参所在的地址)。
2)再看一个例子,如果换成是数组变量呢?这里为了方便操作只放了一个元素,多个元素加个循环就好了。
#include<stdlib.h> #include<iostream> using namespace std; void exchange(int x[], int y[]){ cout << x <<" "<< x[0] << endl; cout << y <<" "<< y[0] << endl; int p = x[0]; x[0] = y[0]; y[0] = p; } int main() { int a[1] = {1}, b[1] = {2}; int *A = a; cout << a[0] <<" "<< a << endl; cout << b[0] <<" "<< b << endl; cout << endl; exchange(a, b); cout << endl; cout << a[0] <<" "<< a << endl; cout << b[0] <<" "<< b << endl; return 0; }会发现,这里就不存在上面整型变量的问题,因为数组传入函数必须是指针的形式,操作的必是指针指向的地址,那么就会存在一个问题,如果想写一个求数组长度的函数怎么办呢?可以使用模板函数,这样传入函数的就是数组本身,可以使用sizeof进行计算。
template<typename T> int Lenth(T& A) { N = sizeof(A)/ sizeof(A[0]); return N; }3)最后再看如果是一个指针变量呢?例如链表中定义:
typedef struct LNode *List; struct LNode { int Data; List Next; }; #include <iostream> #include <stdlib.h> using namespace std; void InitList(List head) { cout << &head << endl; head = NULL; } void InitList1(List *head) { cout << &*head << endl; *head = NULL; } int main() { List PtrL; cout << PtrL <<" "<< &PtrL << endl; InitList(PtrL); cout << PtrL <<" "<< &PtrL << endl; InitList1(&PtrL); cout << PtrL <<" "<< &PtrL << endl; return 0; }运行结果:
0x10 0x61fe18 0x61fdf0 0x10 0x61fe18 0x61fe18 0 0x61fe18 [Done] exited with code=0 in 0.299 seconds很明显可以看出,指针变量和其他的单变量一样,直接传递近函数的话就会复制一份,所有这里需要二维指针来解决。要注意指针变量也是变量,有自己存储的地址,而变量本身存储的值是一个地址,在链表中,这个值就是首元结点(或者是头结点)的地址,即指向该结点。下面这种方式也可以:
void InitList2(List &head){ head = NULL; }这里有一道题可以帮助理解
