C语言使用相关汇总2

本文介绍了C语言中浮点数与整数的比较方法,数组的定义和使用,包括空数组和不定长数组的处理,以及动态内存管理函数`realloc`的工作原理。此外,还探讨了C语言内存的堆、栈存储区,以及`#pragma pack`和`typedef`与`#define`的用法及差异。这些基础知识对于理解和优化C语言程序至关重要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录:

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

14、数组

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

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

16、堆、栈、存储区

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

17、#pragma pack

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


下续:C语言使用相关汇总3。 


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)

floor函数用于返回 ≤ 浮点参数值的最大整数。

14、数组

1)定义一个空数组

输出3,6,9,12......

#include"stdio.h"

void main(void)
{
    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); //初始化为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,此时,原来的指针仍然有效。

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

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

看一下示例代码:

#include  "stdio.h"
#include  "stdlib.h"

int main(int argc, char* argv[], char* envp[])  
{
    int ValueInput;  
    int n;  
    int *numbers1;  
    int *numbers2;

    numbers1=NULL;  
    if((numbers2=(int *)malloc(5*sizeof(int)))==NULL)//为numbers2在堆中分配内存空间  
    {  

        printf("malloc memory unsuccessful");  
        exit(1);  
    }

    printf("numbers2 addr: %8X\n",(int)numbers2);  
    for(n=0;n<5;n++) //初始化  
    {  
        *(numbers2+n)=n;  
        //printf("numbers2's data: %d\n",*(numbers2+n));  
    }  
    printf("Enter new size: ");  
    scanf("%d",&ValueInput);  
//重新分配内存空间,如果分配成功的话,就释放numbers2指针, 但是并没有将numbers2指针赋为NULL,也就是说释放掉的是系统分配的堆空间,  
//和该指针没有直接的关系,现在仍然可以用numbers2来访问这部分堆空间,但是现在的堆空间已经不属于该进程的了。  
    numbers1=(int *)realloc(numbers2,(ValueInput+5)*sizeof(int));  
    if(numbers1==NULL) 
    {  
        printf("Error (re)allocating memory");  
        exit(1);  
    }  
    printf("numbers1 addr: %8X\n",(int)numbers1);  
    for(n=0;n<<span style="font-family: 宋体; font-size: 12px;">ValueInput;n++)//新数据初始化
    {  
        *(numbers1+5+n)=n+5;  
        //printf("numbers1' new data: %d\n",*(numbers1+5+n));  
    }  
    printf("\n");  
    free(numbers1);//释放numbers1,此处不需要释放numbers1,因为在realloc()时已经释放  
    numbers1=NULL;  
    //free(numbers2);//不能再次释放  
    return 0;
}  

如果当前内存段后有足够的空间,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编译器中,参数是由右往左入的,然后是函数中的局部变注意静态变量是不入的。

当本次函数调用结束后,局部变量先出,然后是参数,最后顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。

堆:一般是在的头部用一个字节存放的大小。中的具体内容由程序员安排。

示例:

int a = 0; //全局初始化区
char *p1; //全局未初始化区
void main()
{
    int b; //栈
    char s[] = "abc"; //栈
    char *p2; //栈
    char *p3 = "12345"; //12345在常量存储区,p3在栈上
    static int c = 0; //静态存储区初始化区
    p1 = (char *)malloc(10); //分配得来10字节的区域 存在堆区
    p2 = (char *)malloc(20); //分配得来20字节的区域 存在堆区
    strcpy(p1, "12345");
//12345放在常量存储区,编译器可能会将它与p3所指向的"12345"优化成一块
}

17、#pragma pack

有关内容:C语言-结构体struct

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

下面以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后面要加分号。


青春时代是一个短暂的美梦,当你醒来时,它早已消失得无影无踪。觉得不错,动动发财的小手点个赞哦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱上电路设计

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值