加载中…
个人资料
liht1634
liht1634
  • 博客等级:
  • 博客积分:0
  • 博客访问:223,741
  • 关注人气:58
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
相关博文
推荐博文
正文 字体大小:

C语言使用相关汇总2

(2016-12-22 16:24:22)
标签:

c语言使用

分类: 编程类

内容包括浮点数与整数比较大小、数组、realloc、堆栈存储区、#pragma pack、typedef和#define的用法与区别紫色文字为超链接,点击自动跳转至其他相关博文。持续更新!

目录:

13、浮点数与整数比较大小

14、数组

1)定义一个空数组   2)不定长数组(realloc见本章第15)

15、realloc更改己经配置内存空间指令

16、堆、栈、存储区

1)C/C++内存的4个区   2)堆和栈中的存储内容

17、#pragma packC程序结构体的内存空间分配原理

18、typedef和#define的用法与区别

99、总结

--------------------------------------------


--------------------------------------------------------------------------------------------------

13、浮点数与整数比较大小

C语言中浮点数不能直接和整数比较大小,一般方法如下。

1)首先将整数转换为浮点数可以用强制类型转换或赋值给double变量;其次两浮点数相减最后差值取绝对值,检查差值与要求精度差距。

#include "math.h"

int equ_double_int(double a, int c)
{
    if(fabs(a-c) 0.00005) 

        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* (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);//初始化为0
UserTime[0] xxx;//象数组那样使用
UserTime++;//等于数组下标加一
UserTime += xxx;//等于下标加xxx
free(UserTime);//用完释放

C++程序

#include "stdio.h"
#include "malloc.h"
int main()
{
    printf("输入数组大小:\n");
    int size;
    scanf("%d",&size);
    int i;
    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释放
    return 0;
}

-------------------------------------------------------------------------------------------------------------

15、realloc更改己经配置内存空间指令

realloc(void *__ptr, size_t __size):更改已经配置的内存空间,即更改由malloc()函数分配的内存空间的大小。

如果将分配的内存减少,realloc仅仅是改变索引的信息。
如果是将分配的内存扩大,则有以下情况:
1)如果当前内存段后面有需要的内存空间,则直接扩展这段内存空间,realloc()将返回原指针。
2)如果当前内存段后面的空闲字节不够,那么就使用(由系统分配)中的第一个能够满足这一要求的内存块,将目前的数据复制到新的位置,并将原来的数据块释放掉,返回新的内存块位置。
3)如果申请失败,将返回NULL,此时,原来的指针仍然有效。

注意:如果调用成功,不管当前内存段后面的空闲空间是否满足要求,都会释放掉原来的指针,重新返回一个指针,虽然返回的

针有可能和原来的指针一样,即不能再次释放掉原来的指针。


看一下示例代码:

1. #include  "stdio.h"

2. #include  "stdlib.h"

3. int main(int argc, charargv[], charenvp[])  

4.  

5.     int ValueInput;  

6.     int n;  

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<<span 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.     return 0;

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 packC程序结构体的内存空间分配原理

在网络协议编程中,经常会处理不同协议的数据报文。一种方法是通过指针偏移的方法来得到各种信息,但这样做不仅编程复杂,而且一旦协议有变化,程序修改起来也比较麻烦。在了解了编译器对结构空间的分配原则之后,我们完全可以利用这一特性定义自己的协议结构,通过访问结构的成员来获取各种信息。这样做,不仅简化了编程,而且即使协议发生变化,我们也只需修改协议结构的定义即可,其它程序无需修改,省时省力。

下面以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 PI 3.1415926
程序中的:area=
PI*r*r 会替换为3.1415926*r*r
如果你把
#define语句中的数字9 写成字母g 预处理也照样带入。

比如4个芯片的地址定义

#define Chip1 (unsigned int) 0<<14

#define Chip2 (unsigned int) 2<<14

#define Chip3 (unsigned int) 1<<14

#define Chip4 (unsigned int) 3<<14 //unsigned int共16位二进制,将3D=0011B左移14位


4个芯片地址

Chip1: 0x0

Chip2: 0x8000

Chip3: 0x4000

Chip4: 0xc000

--------------------------------------
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、总结

1)C语言常用数据类型内存存储形式

2转义字符\

3详解C程序volatile关键字

4C程序结构体的内存空间分配原理

5void与void*详解

6数组指针和指针数组的区别

7指针函数与函数指针的区别

8char *a与char a[]的区别


--------------------------------------------------------------------------------------------------

0

阅读 评论 收藏 转载 喜欢 打印举报/Report
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有