目录:
13、浮点数与整数比较大小
14、数组
1)定义一个空数组 2)不定长数组(realloc见本章第15)
15、realloc更改己经配置内存空间指令
16、堆、栈、存储区
1)C/C++内存的4个区2)堆和栈中的存储内容
17、#pragma
pack(C程序结构体的内存空间分配原理)
18、typedef和#define的用法与区别
99、总结
--------------------------------------------
--------------------------------------------------------------------------------------------------
13、浮点数与整数比较大小
C语言中浮点数不能直接和整数比较大小,一般方法如下。
1)首先将整数转换为浮点数可以用强制类型转换或赋值给double变量;其次两浮点数相减最后差值取绝对值,检查差值与要求精度差距。
#include "math.h"
int equ_double_int(double a, int c){if(fabs(a-c)
return(1);
else
return(0);}
2)将整数乘以1.0,比如int
a;
a*1.0编译器认为就是一个浮点数。
3)类型强制转换。
4)float
x=10.001;int
a=10;
if(floor(x+0.0005)>a)
-------------------------------------------------------------------------------------------------------------
14、数组
1)定义一个空数组
输出3,6,9,12......
#include"stdio.h"
void
main()
{
int array[100];//空数组的定义
int
i;
//循环赋值
for(i=0; i<100;
i++)
array[i] = (i + 1) *
3;
//输出
for(i=0; i<100;
i+=)
printf("array[%d] = %d\n", i,
array[i]);
}
-----------------------------------------
2)不定长数组(realloc见本章第15)
①手里有一小段MATLAB程序需要转化成C语言。MATLAB里输入的矩阵可以是任意大小的,但是C语言里的数组一定要是固定大小,对于大小不能确定的数组我想到了用malloc动态申请内存,但是就算用malloc也必须是申请一定大小的存储空间(比如键盘输入的).....但是我的matlab里的向量的长度是根据以前的数据算出来的,在MATLAB里非常容易得到向量长度,一句length(a)就知道向量长度了,MATLAB里不知道长度的向量怎样转化成C语言里的数组并且可以求得其元素个数?
假设数组存的是int型,那么你先申请10个元素int* a = (int*)malloc(sizeof(int)*10);如果又来了一个元素,那么你就可以a=(int *)realloc(a,11*sizeof(int));//更改已经配置的内存空间,动态分配地址然后不够再追加求元素个数int i,n=1;for(i = 0;(a+i)!=NULL;i++);n=i+1;//n就是元素个数
如果你定义的是int型数组比如 int a[10];它的长度就更简单了,n = sizeof(a)/sizeof(int)
②用指针,如:long *UserTime = (long *)malloc(size);//size是你动态需要的大小然后就可以:memset(UserTime,0,size);//初始化为0UserTime[0] = xxx;//象数组那样使用UserTime++;//等于数组下标加一UserTime += xxx;//等于下标加xxxfree(UserTime);//用完释放
③C++程序
#include"stdio.h"#include"malloc.h"intmain(){printf("输入数组大小:\n");intsize;scanf("%d",&size);inti;char*array
= (char*)malloc(size
*sizeof(int));for(i=0;i{printf("请输入数组元素!\n");scanf("%d",&array[i]);printf("array[%d]=%d\n",i,array[i]);}free(array);//malloc申请的内存free来释放,new申请的内存用delete释放return0;}
-------------------------------------------------------------------------------------------------------------
15、realloc更改己经配置内存空间指令
realloc(void *__ptr, size_t __size):更改已经配置的内存空间,即更改由malloc()函数分配的内存空间的大小。
如果将分配的内存减少,realloc仅仅是改变索引的信息。如果是将分配的内存扩大,则有以下情况:1)如果当前内存段后面有需要的内存空间,则直接扩展这段内存空间,realloc()将返回原指针。2)如果当前内存段后面的空闲字节不够,那么就使用堆(由系统分配)中的第一个能够满足这一要求的内存块,将目前的数据复制到新的位置,并将原来的数据块释放掉,返回新的内存块位置。3)如果申请失败,将返回NULL,此时,原来的指针仍然有效。
注意:如果调用成功,不管当前内存段后面的空闲空间是否满足要求,都会释放掉原来的指针,重新返回一个指针,虽然返回的
指针有可能和原来的指针一样,即不能再次释放掉原来的指针。
看一下示例代码:
1.#include"stdio.h"
2.#include"stdlib.h"
3.intmain(intargc,char* argv[],char* envp[])
4.{
5.intValueInput;
6.intn;
7.int*numbers1;
8.int*numbers2;
9.numbers1=NULL;
10.
11.if((numbers2=(int*)malloc(5*sizeof(int)))==NULL)//为numbers2在堆中分配内存空间
12.{
13.printf("malloc memory unsuccessful");
14.exit(1);
15.}
16.
17.printf("numbers2 addr: %8X\n",(int)numbers2);
18.
19.for(n=0;n<5;n++)//初始化
20.{
21.*(numbers2+n)=n;
22.//printf("numbers2's data: %d\n",*(numbers2+n));
23.}
24.printf("Enter new size: ");
25.scanf("%d",&ValueInput);
26.//重新分配内存空间,如果分配成功的话,就释放numbers2指针,
27.//但是并没有将numbers2指针赋为NULL,也就是说释放掉的是系统分配的堆空间,
28.//和该指针没有直接的关系,现在仍然可以用numbers2来访问这部分堆空间,但是
29.//现在的堆空间已经不属于该进程的了。
30.numbers1=(int*)realloc(numbers2,(ValueInput+5)*sizeof(int));
31.if(numbers1==NULL)
32.{
33.printf("Error (re)allocating memory");
34.exit(1);
35.}
36.printf("numbers1 addr: %8X\n",(int)numbers1);
37.
41.
42.for(n=0;n<
style="font-family: 宋体; font-size:
12px;">ValueInput;n++)//新数据初始化
43.{
44.*(numbers1+5+n)=n+5;
45.//printf("numbers1' new data: %d\n",*(numbers1+5+n));
46.}
47.printf("\n");
48.free(numbers1);//释放numbers1,此处不需要释放numbers1,因为在realloc()时已经释放
49.numbers1=NULL;
50.//free(numbers2);//不能再次释放
51.return0;
52.}
如果当前内存段后有足够的空间,realloc()返回原来的指针:
1.yugsuo@ubuntu:~/linux/memange$ gcc -g -o realloc realloc_example.c
2.yugsuo@ubuntu:~/linux/memange$ ./realloc
3.numbers2 addr: 8AFC008
4.Enter new size: 10
5.numbers1 addr: 8AFC008
如果当前内存段后没有足够的空间,realloc()返回一个新的内存段的指针:
1.yugsuo@ubuntu:~/linux/memange$ ./realloc
2.numbers2 addr: 9505008
3.Enter new size: 1000000
4.numbers1 addr: B716F008
--------------------------------------------------------------------------------------------------
16、堆、栈、存储区
1)C/C++内存的4个区
在C/C++中,内存分成4个区,他们分别是堆、栈、静态存储区和常量存储区。①栈:就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区。里面的变量通常是局部变量,函数参数等。栈就象车站一样,只是一个临时场所。
在函数体中定义的变量通常是在栈上,m是局部变量:在栈中分配,在函数func被调用时才被创建,生命周期为函数func内。m每次调用func都会创建,函数结束就销毁。
②堆:又叫自由存储区,它是在程序执行的过程中动态分配的,它最大的特性就是动态性。由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制(程序员分配),一般一个malloc就要对应一个free。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。如果分配了堆对象,却忘记了释放,就会产生内存泄漏。而如果已释放了对象,却没有将相应的指针置为NULL,该指针就是“悬挂指针”。
用malloc, calloc,
realloc(详见本章15、realloc更改己经配置内存空间指令)等分配内存的函数分配得到的就是在堆上。
③静态存储区:所有的静态变量、全局变量都于静态存储区分配。初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束释放。
在所有函数体外定义的是全局变量,加了static修饰符后不管在哪里都存放在静态存储区,在所有函数体外定义的static变量表示在该文件中有效,不能extern到别的文件用,在函数体内定义的static表示只在该函数体内有效。n是全局变量:储存在静态存储区,进入main函数之前就被创建,生命周期为整个源程序。n只创建一次。
④常量存储区:这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然你要通过非正当手段也可以修改,而且方法很多)常量字符串都存放在常量存储区,返回的是常量字符串的首地址。另外函数中的“12345”这样的字符串存放在常量存储区。
char *s中的s是指针,而指针是指向一块内存区域,它指向的内存区域的大小可以随时改变,而且当指针指向常量字符串时,它的内容是不可以被修改的,否则在运行时会报错。char s[]中的s是数组首地址,而数组首地址对应着一块内存区域,其地址和容量在生命期里不会改变,只有数组的内容可以改变。
---------------------------------
2)堆和栈中的存储内容
①栈:在函数调用时,第一个进栈的是主函数中的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。
当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。
②堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容由程序员安排。
③示例
1 int a = 0; //全局初始化区2 char *p1; //全局未初始化区3 void main()
4 {
5 int b; //栈6 char s[] = "abc"; //栈7 char *p2; //栈8 char *p3 = "12345"; //12345在常量存储区,p3在栈上9 static int c = 0; //静态存储区初始化区10 p1 = (char *)malloc(10); //分配得来10字节的区域 存在堆区11 p2 = (char *)malloc(20); //分配得来20字节的区域 存在堆区12 strcpy(p1, "12345");
13 //12345放在常量存储区,编译器可能会将它与p3所指向的"12345"优化成一块14 }
--------------------------------------------------------------------------------------------------
17、#pragma
pack(C程序结构体的内存空间分配原理)
在网络协议编程中,经常会处理不同协议的数据报文。一种方法是通过指针偏移的方法来得到各种信息,但这样做不仅编程复杂,而且一旦协议有变化,程序修改起来也比较麻烦。在了解了编译器对结构空间的分配原则之后,我们完全可以利用这一特性定义自己的协议结构,通过访问结构的成员来获取各种信息。这样做,不仅简化了编程,而且即使协议发生变化,我们也只需修改协议结构的定义即可,其它程序无需修改,省时省力。
下面以TCP协议首部为例,说明如何定义协议结构。其协议结构定义如下:
#pragma pack(1)
//按照1字节方式进行对齐 设置结构体的边界对齐为1个字节,也就是所有数据在内存中是连续存储的。
struct TCPHEADER
{
shortSrcPort;//16位源端口号
shortDstPort;//16位目的端口号
intSerialNo;//32位序列号
intAckNo;//32位确认号
unsignedcharHaderLen:4;//4位首部长度
unsignedcharReserved1:4;//保留16位中的4位
unsignedcharReserved2:2;//保留16位中的2位
unsignedcharURG:1;
unsignedcharACK:1;
unsignedcharPSH:1;
unsignedcharRST:1;
unsignedcharSYN:1;
unsignedcharFIN:1;
shortWindowSize;//16位窗口大小
shortTcpChkSum;//16位TCP检验和
shortUrgentPointer;//16位紧急指针
};
#pragm apop()
//取消1字节对齐方式
#pragma
pack规定的对齐长度,实际使用的规则是:
结构,联合,或者类的数据成员,第一个放在偏移为0的地方,以后每个数据成员的对齐,按照#pragma
pack指定的数值和这个数据成员自身长度中,比较小的那个进行。 但是,当#pragma
pack的值等于或超过最长数据成员的长度的时候,这个值的大小将不产生任何效果。
而结构整体的对齐,则按照结构体中最大的数据成员进行。
--------------------------------------------------------------------------------------------------
18、typedef和#define的用法与区别
1)#define是预处理指令,在编译预处理时进行简单的替换,不作正确性检查,不管含义是否正确照样带入,只有在编译已被展开的源程序时才会发现可能的错误并报错。例如:#define PI3.1415926
程序中的:area=PI*r*r 会替换为3.1415926*r*r
如果你把#define语句中的数字9 写成字母g 预处理也照样带入。
--------------------------------------2)typedef是在编译时处理的。它在自己的作用域内给一个已经存在的类型一个别名,But you cannot use the
typedef specifier inside a function definition。
--------------------------------------3)typedef int * int_ptr;
与#define int_ptr int *
作用都是用int_ptr代表 int * ,但是二者不同,正如前面所说 ,#define在预处理时进行简单的替换,而typedef不是简单替换
,而是采用如同定义变量的方法那样来声明一种类型。也就是说;
#define int_ptr int *
int_ptr a, b; //相当于int * a, b; 只是简单的宏替换typedef int* int_ptr;
int_ptr a, b; //a, b 都为指向int的指针,typedef为int* 引入了一个新的助记符这也说明了为什么下面观点成立 :
typedef
(int *) pint ;
const
pint p ;//p不可更改,但p指向的内容可更改
pint是一种指针类型const
pint p 就是把指针给锁住了,p不可更改
#define
PINT (int *)
const
PINT p ;//p可更改,但是p指向的内容不可更改。
const
PINT p 是const int * p 锁的是指针p所指的对象。
--------------------------------------
4) #define不是语句,不要在行末加分号,否则会连分号一块置换。typedef后面要加分号。
--------------------------------------------------------------------------------------------------
99、总结
--------------------------------------------------------------------------------------------------