专题:
动态内存分配(所有高级语言,没有C里深刻)
传统数组的缺点:
1.数组长度必须事先指定,而且只能是常整数,不能是变量
例子inta[5];//必须事先指定,而且只能是常整数
intlen=5;inta[len];//error
2.传统形式定义的数组,该数组的内存程序员无法手动释放
数组一旦定义,系统为数组分配的内存空间就会一直存在,除非数组所在的函数运行终止。
在一个函数运行期间,系统为该函数中的数组分配的空间会一直存在。直到该函数运行完毕时,数组的空间才会被系统自动释放。
例子:voidf(void){inta[5]={1,2,3,4,5};....}
//数组a占20个字节的内存空间,程序员无法手动编程释放它,数组a只能在f()函数结束被系统释放
3.数组的长度一旦定义,数组长度就不能再更改。
数组的长度不能在函数运行的过程中动态的扩充或缩小
4.传统方式定义的数组不能跨函数使用
A函数定义的数组,只有在A函数运行期间才可以被其他函数使用,
但A函数运行完毕后,A函数中的数组将无法在被其他函数使用。
#include<stdio.h>
voidg(int*pArr,intlen)
{
pArr[2]=88;//parr[2]==a[2]等价于
}
voidf(void)
{
inta[5]={1,2,3,4,5};//数组a只在f()执行时有效
g(a,5);
printf("%d\n",a[2]);
}
intmain(void)
{
f();//结果:88
//printf("a[0]=%d\n",a[0]);//error
return0;
}
为什么需要动态分配内存
很好的解决的了传统数组的4个缺陷
动态内存分配举例_动态数组的构造难点
/*2011-05-01
malloc是memory(内存)allocate(分配)的缩写
*/#include<stdio.h>
#include<malloc.h>动态内存空间是怎么造出来的?
intmain(void)
{
inti=5;//分配了4个字节,静态分配
int*p=(int*)malloc(100);
/*
1.要使用malloc函数,必须要添加malloc.h头文件
2.malloc函数只有一个形参,并且形参是整型
3.100表示请求系统为本程序分配()个字节
4.malloc函数只能返回第一个字节的地址,
并且这个地址被强制类型转化成存放整型变量的地址,传达出指向整型变
量的信息
5.系统分配了104个字节的内存空间,p变量本身占4个字节,p所指向的内存占100个字节
6.p本身所占的内存是静态分配的,p所指向的内存是动态分配的
*/
free(p);
//free(p)表示把p说指向的内存空间给释放掉,
//p本身的内存不能释放,只有main函数终止时,由系统自动释放
*p=5;
//*p代表的就是一个这int变量,*p这个整型变量的内存分配方式和inti=5;不同。//*p是内存是动态分配的,inti是静态的。
printf("同志们好!\n");
return0;
}
--------------------------------------------------------------/*
2011-05-01
目的:malloc使用_2
*/
#include<stdio.h>
#include<malloc.h>
voidf(int*q)//q是p的拷贝或副本q等价于p*q等价于*p*q=200则*p=200{
//*p=200;//errorf()没有p变量,p是在main()函数定义的
//q=200;//q是指针变量,200是整数
*q=200;//OK!
//**q语法错误!*q整型变量,只有指针变量前可以加*
//free(q);//把q指向的内存释放掉
}
intmain(void)
{
int*p=(int*)malloc(sizeof(int));
*p=10;//sizeof(int)=4;
printf("%d\n",*p);//10
f(p);
printf("%d\n",*p);//200
//f()函数中free(q),则输出-572662307
return0;
}
/*
2011-05-02
目的:动态一维数组示例
realloc(pArr,100)
//扩充动态内存空间(原来50变100;原来150变100)
//保留原来动态内存中未被截取的内容
*/
#include<stdio.h>
#include<malloc.h>
intmain(void)
{
//inta[5];//系统分配20个字节的空间给数组a
intlen;
int*pArr;
printf("请输入你要存放的元素个数:");
scanf("%d",&len);//5
pArr=(int*)malloc(4*len);//pArr指向这20个字节动态空间的前4个字节/*
动态的构造了一个一维数组,该数组的长度len,数组名是pArr,数组元素类型是int类似与intpArr[len]l;len可以变化
*/
//对一维数组进行操作,如:对动态一维数组进行赋值
for(inti=0;i<len;++i)
scanf("%d",&pArr[i]);
printf("动态数组元素为:\n");
//对一维数组进行输出
for(i=0;i<len;++i)
printf("%d\n",pArr[i]);
free(pArr);//动态空间被释放
printf("%d\n",*(pArr+1));
//动态空间被释放,原来动态数组数元素内容为垃圾值-572662307
return0;
}
/*------------在VC++6.0输出结果:
请输入你要存放的元素个数:4
46810
动态数组元素为:
4
6
8
10
*/
使用动态数组的优点:
1.动态数组长度不需要事先给定;
2.内存空间可以手动释放;
3.在程序运行中,动态内存空间大小可以通过realloc函数手动扩充或缩小静态内存和动态内存的比较
静态内存是由系统自动分配,有系统自动释放
静态内存是在栈分配的
动态内存是由程序员手动分配,手动释放
动态内存是在堆分配的
/*
2011-05-02
目的:多级指针
/
#include<stdio.h>
intmain(void)
{
inti=10;//i
int*p=&i;//*p=i;
int**q=&p;//
int***r=&q;
//r=&p;
printf("i
printf("i
printf("i
printf("i
return0;
}
/*-----------在VC++6.0输出结果:
i=10
i=10
i=10
i=10
*/
#include<stdio.h>
//多级指针在函数中的应用
voidf(int**q)
{//error!=%d\n",=%d\n",=%d\n",=%d\n",因为r是int***类型,只能存放int**类型变量的地址***r);**q);*p);i);
**q=100;
}//*q就是p
voidg()
{
inti=10;
int*p=&i;
printf("i=%d*p=%d\n",i,*p);
&p就是int**类型f(&p);//p是int*类型
printf("i=%d
}
intmain(void)
{
g();
return0;
}
/**p=%d\n",i,*p);
-----------在VC++6.0输出结果:i=10*p=10
i=100*p=100
*/
#include<stdio.h>
#include<malloc.h>
voidf(int*q)//q是p的拷贝副本{
*q=1;
}
voidg(int**r)
{
**r=2;
}
voidh(int***s)
{
***s=3;
}
voidi(int****t)
{
****t=4;
}
//要想修改函数变量的值,只能发送该变量的地址,修改一个以上的值,必须用指针intmain(void)
{
int*p=(int*)malloc(4);
printf("*p=%d\n",*p);//垃圾值
f(p);//调用的是指针
printf("*p=%d\n",*p);//1
g(&p);//调用的是指针变量的地址
printf("*p=%d\n",*p);//2
//h(&(&p));//errorC2102:'&'requiresl-value
int**pp=&p;//pp是存放p地址的指针,int**整型指针的指针类型
h(&pp);//调用的是存放p指针的指针的地址int***整型指针的指针的指针类型printf("*p=%d\n",*p);//3
int***ppp=&pp;
i(&ppp);//调用的是一个三级指针的指针的地址,int****整型四级指针printf("*p=%d\n",*p);//4
return0;
}
跨函数使用内存的问题难点
/*
2011-05-02
目的:跨函数使用内存
函数内的静态空间,不能被其他函数调用访问
*/
#include<stdio.h>
voidf(int**q)//理解为int**q
{
inti=5;
//*q等价于p*p和**q都不等价于p
//*q=i;//error*q等价于p推出p=i;错!
*q=&i;
}
intmain(void)
{
int*p;//**q=*p=i;
f(&p);
printf("%d\n",*p);
/*结果:5
本语句语法没有问题,但逻辑上有问题
内存越界:程序访问了一个不该被访问的内存
函数内的静态空间,不能被其他函数调用访问
函数中的内存空间,随函数终止而被释放。
内存空间释放后的内容不属于其他函数,其他函数无权限访问。
但释放后的内存空间的地址是可以被其他函数读取的。
指针变量可以存贮任何函数中静态内存空间的地址,p都能存垃圾,p想存谁存谁
*/
return0;
}
/*
2011-05-02
目的:动态内存可以跨函数访问
程序运行在栈顶进行
静态空间是在栈里面分配的,函数终止本质叫做出栈,所以静态空间随着函数终止而释放,动态空间是在堆里面分配的,与栈无关,与函数终止无关,不随着函数终止而释放。
可以用free()释放
*/
#include<stdio.h>
#include<malloc.h>
voidf(int**q)//*q等价p已经声明了q的类型为int**
{
*q=(int*)malloc(sizeof(int));//sizeof(整数类型)
/*
不要用4,因为c语言只规定shortint字节数<int字节数<longint字节数,没有规定明确的字节数.
不同软件系统可能出现不同,统一用sizeof(int)来获取实际值
int*p;在p声明的情况下,
构造动态空间也可以写成p=(int*)malloc(sizeof(int));
*/
//*q等价p,等价于p=(int*)malloc(sizeof(int));
//q=5;//error!q指针
//*q=5;
**q=5;//error!p=5//OK!等价于*p=5
}
intmain(void)
{
int*p;
f(&p);//只有调用变量的地址,才能改变变量的值
printf("%d\n",*p);
//f函数中,没有free(q);所以动态空间仍然保留,动态空间中的内容可以被访问return0;
}
/*
-----------在VC++6.0输出结果:
5
*/
枚举
什么是枚举
把一个事物所以可能的取值一一列举出来
/*
日期:2011-05-04
目的:枚举
*/
#include<stdio.h>
//自定义了一个数据类型,并没有定义变量,该数据类型的名字enumWeekDay
enumWeekDay
{
//MonDay,TuesDay,WednesDay,ThursDay,FriDay,SaturdDay,Sunday
MonDay=10,TuesDay,WednesDay,ThursDay,FriDay,SaturdDay,Sunday
};//分号
intmain(void)
{
//intday;//day定义成int类型范围太大不合适,day的取值只可能有7个(0-6),浪费空间
enumWeekDayday=FriDay;//初始化一个enumWeekDay类型变量day
printf("%d\n",day);
return0;
}
/*
-----------在VC++6.0输出结果:
4
14
*/
怎么使用枚举
/*
日期:2011-05-04
目的:枚举2
*/
#include<stdio.h>
enumweekday
{
MonDay,TuesDay,WednesDay,ThursDay,FriDay,SaturdDay,Sunday
};
voidf(enumweekdayi)//本函数的目的只是期望接受0-6之间的数字,将形参定义为枚举
{
switch(i)
{
case0:
printf("MonDay!\n");
break;
case1:
printf("TuesDay!\n");
break;
case2:
printf("WednesDay!\n");
break;
case3:
printf("ThrusDay!\n");
break;
case4:
printf("FriDay!\n");
break;
case5:
printf("ThursDay!\n");
break;
case6:
printf("SunDay!\n");
break;
}
}
intmain(void)
{
f(FriDay);//虽然FriDay本质上就是5,但直接写出f(5);就是错的,也不可能写成
return0;
}
枚举的优缺点
优点:代码更安全,比较直观
缺点:书写麻烦
位运算符
约翰·冯·诺依曼(JohnVonNouma,1903-1957),美藉匈牙利人计算机之父:2大贡献
二进制
计算机设备分类:运算器控制器存储器输入设备输
出设备
什么是进制
数字是本质,进制只是不同表现方式
一个十六进制位,要用4个二进制数表示,(1)16=(0001)
2前面补齐二进制逢十进制八进制十六进制
二进一
逢十进一dec逢八进一oct0数字inti=05;逢十六进一hex0x数字0X数字
inti=0x5;inti=0X5;
生活中:七进制七天进周十二进制十二月进年二十四进制二十四小时进日六十进制六十分钟进小时
六十秒钟进分钟
汇编里
1101B二进制1357O八进制2049D十进制3FB9H十六进制十进制(D)二进制(B)000111210231134100451015611067111781000109100111101010121110111312110014131101151411101615111117161000020
八进制(O)十六进制(H)
01234567
89a(A)b(B)c(C)d(D)e(E)f(F)10
017=7+1*8=150x17=7+1*16=25
1234=4+1*10三次方+2*10二次方+3*10一次方0x32c=c+3*16二次方+2*16一次方=4354最高幂数是位数-1
#include<stdio.h>
intmain(void)
{
inti=0x32c;
printf("i=%d\n",i);
printf("i=%x\n",i);
printf("i=%o\n",i);
/*
printf的用法
%d以十进制输出
%x或%X以十六进制输出
%o或%O以八进制输出
*/
return0;
}
#include<stdio.h>
intmain(void)
{
inti=1000;
print("%X\n",i)//3E8
printf("%#X\n",i)//OX3E8%#X推荐
return0;
}
补码:
原码:
也叫符号绝对值
最高位0表示正1表示负,其余二进制位是该数字的绝对值的二
进制位
在计算机中,从未被使用!
反码
反码运行不便,也没有在计算机中应用
-----------------------------------------
移码
表示数值平移n位,n称为移码量
移码主要用于浮点数的阶码的存储
-----------------------------------------
补码地址是内存单元编号0到4G-12的32次方-1
32个0,1
主要解决整数的存储int4字节32位个0,1
已知十进制求二进制总线32位,
求正整数的二进制
除2取余,直到商为零,余数倒序排列
求负整数的二进制
先求出与该负数相对应的正整数的二进制代码,
然后,将所有位取反,末尾加1,不够位数时,左边补一-5510101001129个1,011
4字节int(-3)011100101补29个1,101
2字节shortint(-3)101补13个1101
(-100)16进制64(16进制)0110,0100反1001,1011FFFFFF9C8位
求零的二进制
全是零
已知二进制求十进制
如果首位是0,则表明是正整数,
按普通方法来求
如果首位是1,则表明是负整数,
将所有位取反,末尾加1,所得数字就是该负数的绝对值如果全是零,则对应的十进制数字就是零+11001,1100
学习目标:
在在VC++6.0中一个int类型变量所能存储的数字的范围是多少(32位系统,32个0,1组合表示的内存单元,8个十六进制数组
合)
int类型变量所能存储的最大正数用十六进制表示:
7FFFFFFF
int类型变量所能存储的绝对值最大负整数用十六进制表
示:80000000
最小负数的二进制代码是多少1(0-031个0)
最大正数的二进制代码是多少0(1-131个1)
已知一个整数的二进制代码求原始的数字按“已知二进制求十
进制”求
数字超过最大正数会怎样
0000-128
不同数据类型转化
占字节小的位数的值丢失最高位.只截取2个数据类型中,所变成负数01111111=1271000
www.99jianzhu.com/包含内容:建筑图纸、PDF/word/ppt 流程,表格,案例,最新,免费下载,施工方案、工程书籍、建筑论文、合同表格、标准规范、CAD图纸等内容。