通过给定的指针直接删除节点没有实际的解决方案,需要做一些技巧。通过给定的要删除的指针将数据从下一个节点复制到当前节点并删除下一个节点。
参考示例:
//Get the Address of the next node
NodePointer temp = Node->pNextNode;//Get the data of next node
Node->iData = temp->iData;//Get the Address of next to next node
Node->pNextNode = temp->pNextNode;//Delete the next nodefree(temp);
结构体内包含多个成员,这些成员之间在内存中是如何存放的呢?
比如:
struct fraction {
int num; // 整数部分
int denom; // 小数部分
};
struct fraction fp;
fp.num = 10;
fp.denom = 2;
这是一个定点小数结构体,它在内存占 8 个字节(这里不考虑内存对齐),两个成员域是这样存储的:
我们把 10 放在了结构体中基地址偏移为 0 的域,2 放在了偏移为 4 的域。
接下来我们做一个这样的操作:
((fraction*)(&fp.denom))->num = 5;
((fraction*)(&fp.denom))->denom = 12;
printf("%d\n", fp.denom); // 输出多少
首先,&fp.denom表示取结构体 fp 中 denom 域的首地址,然后以这个地址为起始地址取 8 个字节,并且将它们看做一个 fraction 结构体。
在这个新结构体中,最上面四个字节变成了 denom 域,而 fp 的 denom 域相当于新结构体的 num 域。
因此:
((fraction*)(&fp.denom))->num = 5
实际上改变的是 fp.denom,而
((fraction*)(&fp.denom))->denom = 12
则是将最上面四个字节赋值为 12。
当然,往那四字节内存写入值,结果是无法预测的,可能会造成程序崩溃,因为也许那里恰好存储着函数调用栈帧的关键信息,也可能那里没有写入权限。
大家初学 C 语言的很多 coredump 错误都是类似原因造成的。
所以最后输出的是 5。
为什么要讲这种看起来莫名其妙的代码?
就是为了说明结构体的本质其实就是一堆的变量打包放在一起,而访问结构体中的域,就是通过结构体的起始地址,也叫基地址,然后加上域的偏移。
其实,C++、Java 中的对象也是这样存储的,无非是他们为了实现某些面向对象的特性,会在数据成员以外,添加一些 Head 信息,比如C++ 的虚函数表。
实际上,我们是完全可以用 C 语言去模仿的。
这就是为什么一直说 C 语言是基础,你真正懂了 C 指针和内存,对于其它语言你也会很快的理解其对象模型以及内存布局。
变量就是可以变化的量,而每个变量都会有一个名字(标识符)。变量占据内存中一定的存储单元。使用变量之前必须先定义变量,要区分变量名和变量值是两个不同的概念。
注意:在定义中不允许连续赋值,如int a=b=c=5;是不合法的。
变量的赋值分为两种方式:
先声明再赋值
声明的同时赋值
C语言中,数据类型可分为:
基本数据类型
构造数据类型
指针类型
空类型四大类
整型数据是指不带小数的数字(int,short int,long int, unsigned int, unsigned short int,unsigned long int):
int short int long int是根据编译环境的不同,所取范围不同。
而其中short int和long int至少是表中所写范围, 但是int在表中是以16位编译环境写的取值范围。
另外 c语言int的取值范围在于他占用的字节数 ,不同的编译器,规定是不一样。
ANSI标准定义int是占2个字节,TC是按ANSI标准的,它的int是占2个字节的。但是在VC里,一个int是占4个字节的。
浮点数据是指带小数的数字。
生活中有很多信息适合使用浮点型数据来表示,比如:人的体重(单位:公斤)、商品价格、圆周率等等。
因为精度的不同又分为3种(float,double,long double):