-
1 课件
-
2 视频
-
3 资料
-
4 练习
赵老师笔记----指针
指针
指针是C语言的灵魂
一、指针的概念
(1)指针是什么??
指针事实上就是一个地址
(2)指针变量
用来存放地址的变量
(3)指针的运算
赋值=、取地址&、取值*、地址加++(+)只能加整数、地址减--(-)相同类型的指针直接相减、关系运算
二、内存相关的事情
外存:外部存储器,硬盘,u盘,光盘,磁带,磁盘
内存:计算机里面所有的执行程序内容及相关数据必须要在内存里才可以运行
物理内存:计算机里面的实实在在的内存
虚拟内存:由操作系统决定,操作系统的位数决定虚拟内存的大小
32位:4G 2^10=1024B=1KB 2^20=1024*1KB=1MB 2^30=1024*1MB=1GB 2^32=4*1GB=4GB
64位:很大很大。。。。。
在32位操作系统下:
4G虚拟内存分为以下几个分区:
3G~4G:内核空间
0x00000000~0x0804800:预留空间
余下:用户空间,程序可用空间部分
.text:代码
.rodata:只读数据区,或者叫文字常量区,用来存放常量的
静态区: (1).data:初始化后的静态全局区,已经初始化的全局变量,静态变量,
(2).bss:未初始化的静态全局区,未初始化的静态变量,全局变量,
.heap(堆):向上生长,动态申请内存时,程序员申请使用,使用完要释放。申请的空间在堆区,它的使用是无名空间,通过地址访问,空间大,效率低
.stack(栈):向下生长,栈顶初始在3G-4G分割处,主要放局部变量(函数内部,复合语句内部定义的变量),有名空间,通过变量名访问,空间小,效率高,由操作系统自动分配、回收
二、指针的定义
(1)定义
数据类型 * 指针变量名;
int *p;//定义了一个指向整型变量的指针
int **pa;//定义一个一个指针,该指针指向整型变量
int ***pb;//也定义了一个指针
#include "stdio.h"
int main(int argc, char *argv[])
{
int a=100;
int *p=&a;
int **pa=&p;
int ***pb=&pa;
char *pc;
printf("a=%d\n",a);
printf("*p=%d\n",*p);
printf("**pa=%d\n",**pa);
printf("***pb=%d\n",***pb);
printf("p=%p\n",p);
printf("&a=%p\n",&a);
printf("pa=%p\n",pa);
printf("p的大小%d\n",sizeof(p));
printf("pc的大小%d\n",sizeof(pc));
printf("pa的大小%d\n",sizeof(pa));
return 0;
}
(2)运算
赋值=、取地址&、取值*、地址加++(+)只能加整数、地址减--(-)相同类型的指针直接相减、关系运算
int a=0x0000124f;//假设a的地址是0x00200000;
int *p=&a;
p=&a;//p=0x00200000
int num;
num=*p;//num=0x0000124f;
#include "stdio.h"
int main(int argc, char *argv[])
{
int a=100,b=200;
int *p,*pa=&b;//定义时就赋值
p=&a;//先定义后赋值
printf("%d\n",a);
printf("%d\n",*p);
printf("%d\n",b);
printf("%d\n",*pa);
printf("%p\n",&b);
printf("%p\n",pa);
return 0;
}
#include "stdio.h"
int main(int argc, char *argv[])
{
#if 0
int b[]={1,2,3,4};
int *pb;
pb=b;
printf("%d\n",*pb);//1
printf("%p\n",pb);//
pb++;
printf("%d\n",*pb);//2
printf("%p\n",pb);//pb=pb+sizeof(int *)
pb=&b[1];
printf("%d\n",*pb);//2
pb++;
printf("%d\n",*pb);//3
#endif
#if 1
int a[][2]={{1,2},{3,4}};
int *p;
p=a[0];//表示将p指针指向第0行,a[0]第0行首地址
printf("%d\n",*p);//1
p++;
printf("%d\n",*p);//2
p=&a[1][0];
printf("%d\n",*p);//3
p++;
printf("%d\n",*p);//4
p=a;
printf("%d\n",*p);//1
p++;
printf("%d\n",*p);//2
p=&a[1][0];
pc=&a[0][1];
int num=p-pc;//相同类型指针运算时,运算结果是指指针移动的次数
printf("%d\n",num);//1
#endif
return 0;
}
三、指针的分类
按照指向的数据类型来分:
1:字符指针
char *p;
2:整型指针
int *p
3.其他简单数据类型指针
double *p;
4.结构体指针
struct student *p;
5.指针的指针
char **p;
6.数组指针
char *a[5];//指针数组
char (*a)[5];//数组指针
7.函数指针
指针大小,32位系统下指针只是一个地址,有四个字节
四、指针和变量的关系
指针可以存放变量的地址编号
访问变量
1。直接通过变量的名称访问
int a=100;
a=200;
2.通过指针来访问
int a=100;
int *p;
p=&a;
*p=200;
使用时注意类型的匹配
如果希望一个指针指向不同类型的变量,
将该指针赋为void *,并注意强制类型转换
#include "stdio.h"
int main(int argc, char *argv[])
{
int a=100;
char b='A';
void *p;
p=&a;
printf("%x\n",*(int *)p);
p=&b;
printf("%c\n",*(char *)p);
return 0;
}
五、指针与数组的关系
1.数组与地址
int a[10];
a[2],*(&a[0]+2),*(a+2)
2.数组元素的引用
①通过数组下标引用
a[2]
②通过地址去引用
*(&a[0]+2),*(a+2)
③通过指针名加下标
int a[10];
int *p=a;
p[2];
④通过指针运算加取值符来引用
*(p+2);
//判断是否是回文
#include "stdio.h"
int main(int argc, char *argv[])
{
char name[5]={'M','A','D','B','M'};
int flag=1;
char *start=name,*end=name+4;
for(;start<=end;start++,end--)
{
if(*start!=*end)
{
flag=0;break;
}
}
if (flag)
printf("该字符串是回文\n");
else
printf("该字符串不是回文\n");
return 0;
}
3.指针的运算
①指针可以加一个整数,表示移动指针整数个元素
int a[10];
int *p=a;
p++;//p是指针变量,可以修改
a++????//a是数组名,也是地址,但是是常量,不能修改
p=P+2;//使得p指针指向了数组的a[2],相当于p=p+2*sizeof(int);
②相同类型的指针可以比较大小,该指针指向同一数组时比较大小有意义
for(;start<=end;start++,end--)
③两个相同类型的指针还可以做减法
char name[5]={'M','A','D','B','M'};
int flag=1;
char *start=name,*end=name+4;
end-start=??? 4
前提:该指针指向同一数组时比较大小有意义
做减法后的结果,表示的是两指针中间有多少个元素
④两相同类型的指针可以互相赋值
char name[5]={'M','A','D','B','M'};
char *start=name,*end=name+4;
start=end;???
指针里面都是放的地址,而且对32位系统来说都是4个字节的地址
如果不同类型的指针变量互相赋值时要强制类型转换,但有可能丢失值
#include "stdio.h"
int main(int argc, char *argv[])
{
unsigned int a=0x1234,b=0x6789;
char *p,*q;
p=(char *)&a;
q=(char *)&b;
printf("*P=%x\n",*p);
printf("*q=%x\n",*q);
p++;
q++;
printf("**************\n");
printf("*P=%x\n",*p);
printf("*q=%x\n",*q);
return 0;
}
如果不同类型的指针变量互相赋值时要强制类型转换,但有可能丢失值
#include "stdio.h"
int main(int argc, char *argv[])
{
unsigned int a=0x1234;
char *p;
int *p2;
p2=&a;
p=(char *)p2;
printf("*P=%x\n",*p);
printf("*p2=%x\n",*p2);
return 0;
}
六、指针数组
①指针和数组
指针:是一个地址
数组:可以存放相同类型的变量
指针数组:是数组,但是数组里放的是指针,该数组是指针的集合
②定义方法
类型 * 数组名[元素个数]
int *p[10];//表达可以容纳是个整型指针的数组
char *b[4]={“hello”,"world","你好",“世界”};
#include "stdio.h"
int main(int argc, char *argv[])
{
char *b[4]={"hello","world","你好","世界"};
int i;
for (i=0;i<4;i++)
// printf("b[%d]=%s\n",i,b[i]);
printf("b[%d]=%s\n",i,*(b+i));
return 0;
}
七、指针的指针
①含义
指针是地址
指针变量本身也有地址
②定义方法
类型(指针类型 【类型 *】) * 变量名
int ** p;
int a;
int *p;
p=&a;
int **q;
q=&p;
*p;
**q;
int ***k;
k=&q;
***k
*(*(*k))
const 修饰指针时,const是右结合
int * const p=&a;//p常量化(只读),但*p可变
int const * p=&a;//*P常量化(只读),但p可变
int const * const p=&a;//*P常量化(只读),p常量化(只读)
八、字符串和指针
1.字符串的概念
若干个字符,并以'\0'结尾的字符集合
2.使用
字符串常量"world"
①char a[10]="world";//局部变量"world"存储在栈区stack,全局变量,静态变量,.data
可以修改,a[0]='p';
②char *p="world";//"world"存储在文字常量区,.rodata
p存放的是"world"的首地址,或者说是字符'w'的地址
内容不可修改,不可以不可以*p='p';
③也可以动态申请空间
malloc(10*sizeof(char))
char *str=(char *)malloc(10*sizeof(char));//动态申请了10个字节的存储空间,堆区heap
strcpy(str,"world");
堆区的内容可以修改
*str='p';可以
3.初始化
①char a[]="world";
②char *p="world";
③堆中存放的字符串,不可以初始化,只能用strcpy,scanf去赋值
char *str=(char *)malloc(10*sizeof(char));
strcpy(str,"world");
scanf("%s",str);
九数组指针
1.二维数组
int a[2][3];//可以看成是2行3列,实际上是连续存放,以行优先存放
数组名是数组的首地址
a[0]是地址
a[1]是地址
a也是地址,
a[0]+1???表示的是指向下一个元素,+sizeof(int)
a+1???表示的是指向下一维数组,下一行,+行元素个数*sizeof(int)
2.数组指针的概念
本身是一个指针,它指向一个数组,加1,跳一个数组,指向下一个数组
定义:
指向的数组的类型 (*指针变量名)[指向数组元素的个数]
int (*p)[3];//定义了一个数组指针,指针指向一个大小为3的整型数组
p+1;//表示地址增加3*sizeof(int)
#include "stdio.h"
int main(int argc, char *argv[])
{
int a[2][3]={1,2,3,4,5,6};
printf("a的地址%p\n",a);
printf("a+1的地址%p\n",a+1);
int (*p)[3];
p=a;
printf("p的值%p\n",p);
printf("p+1的值%p\n",p+1);
printf("利用p取得第1行第2元素的值%d\n",p[1][2]);
p++;
printf("利用p取得第0行第2元素的值%d\n",p[0][2]);
return 0;
}
3.二维数组指针
int (*P)[2][3];
int a[4][2][3]={{1,2,3,4,5,6},{6,7,8,9,10,11,12}};
#include "stdio.h"
int main(int argc, char *argv[])
{
int a[4][2][3]={{1,2,3,4,5,6},{6,7,8,9,10,11}};
int (*p)[2][3];
printf("a的地址%p\n",a);
printf("a+1的地址%p\n",a+1);
p=a;
printf("p的值%p\n",p);
printf("p+1的值%p\n",p+1);
printf("利用p取得第一矩阵第1行第2元素的值%d\n",p[1][1][2]);
p++;
printf("利用p取得第0矩阵第1行第2元素的值%d\n",p[0][1][2]);
return 0;
}
4.总结
一维数组名字取地址,变成一个一维数组指针
int a[10];
a+1跳一个整型的元素,a[1]的地址
&a,变成一个一维数组指针,相当于int (*p)[10]类型的
(&a)+1,移动整个数组,
二维数组名字取地址,变成一个二维数组指针
#include "stdio.h"
int main(int argc, char *argv[])
{
int a[2][3]={1,2,3,4,5,6};
printf("a的地址%p\n",a);
printf("a+1的地址%p\n",a+1);
int (*p)[2][3];
p=&a;
printf("p的值%p\n",p);
printf("p+1的值%p\n",p+1);
printf("利用p取得第1行第2元素的值%d\n",((*p)[1][2]));
return 0;
}
5.数组名字和指针变量名字的区别
数组名是常量,指针变量是变量
int a[10]
int *p=a;
p[2],a[2]
*(p+2),*(a+2)
p++
a++???
a和p在引用数组元素时等价
①但a是常量,不能修改
p是变量,可以修改
p++
*p
②对&a,表示是一个数组指针
对&p,表示是一个二级指针,指向指针的指针
③对多维数组名*a不是取内容,而是对其指针降级
int a[2][3]
a 第0行首地址
*a,第0行第0列首地址 降级
&a,相当于得到第0个矩阵的首地址,或者说是二维数组指针 升级
十、函数指针
引例
#include "stdio.h"
int fun(int a,int b)
{
return a+b;
}
int fun2(int a,int b)
{
return a-b;
}
int main(int argc, char *argv[])
{
int x=30,y=20,sum;
int (*p2)(int a,int b)=fun;//函数指针
int (*p[2])(int a,int b)={fun,fun2};//函数指针数组
sum=p[0](x,y);
printf("sum=%d\n",sum);
printf("***********\n");
sum=p[1](x,y);
printf("sum=%d\n",sum);
return 0;
}
1.函数与指针的关系
①形参可能是指针变量
②返回值是指针变量
③函数本身是指针
2.函数传参
①值传递
调用函数时传值为值传递只是简单的将实参值复制传递给形参,并不改变实参的值
#include "stdio.h"
void swap(int a ,int b)
{
int temp;
temp=a;
a=b;
b=temp;
}
int main(int argc, char *argv[])
{
int x=30,y=20;
printf("x=%d,y=%d\n",x,y);
printf("*********after swap***********\n");
swap(x ,y);
printf("x=%d,y=%d\n",x,y);
return 0;
}
②传地址
将实参地址传给形参,这样就能改变实参的值,叫传地址
#include "stdio.h"
void swap(int * a ,int * b)
{
int temp;
temp=*a;
*a=*b;
*b=temp;
}
int main(int argc, char *argv[])
{
int x=30,y=20;
printf("x=%d,y=%d\n",x,y);
printf("*********after swap***********\n");
swap(&x ,&y);
printf("x=%d,y=%d\n",x,y);
return 0;
}
另例:
#include "stdio.h"
void swap(int ** a ,int ** b)
{
int *temp;
temp=*a;
*a=*b;
*b=temp;
}
int main(int argc, char *argv[])
{
int x=30,y=20;
int *p=&x,*q=&y;
printf("x=%d,y=%d\n",x,y);
printf("x地址%p,y地址%p\n",&x,&y);
printf("*********after swap***********\n");
swap(&p ,&q);
printf("*p=%d,*q=%d\n",*p,*q);
printf("x=%d,y=%d\n",x,y);
return 0;
}
总结:要想改变主调函数中变量的值,必须传变量的地址
而且
③传数组
给函数传数组,能不能将数组的整体内容传给形参
只能传数组的地址
//给一个数组,利用一个函数将该数组逆序
#include "stdio.h"
void swap(int a[],int num)
{
int t;
int *s,*e;
for (s=a,e=a+num-1;s<e;s++,e--)
{
t=*s;
*s=*e;
*e=t;
}
}
#if 0
void swap(int *a,int num)
{
}
#endif
int main(int argc, char *argv[])
{
int a[5]={1,2,3,4,5};
int i;
for (i=0;i<5;i++)
printf("%d ",a[i]);
printf("\n*********after swap***********\n");
swap(a,5);
for (i=0;i<5;i++)
printf("%d ",a[i]);
return 0;
}
3.函数返回值
函数返回值是指针时,那些存储区的指针才可以返回???
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
char *fun1(void)//.rodata区中的地址可以返回,只读
{
return "hello world!";
}
int *fun2(void)//.data中的地址可以返回,可读可写
{
static int a=123;
a++;
return &a;
}
int *fun3(void)//.bss中的地址可以返回,可读可写
{
static int a;
a=555;
return &a;
}
char *fun4(void)//.stack中的地址不能返回
{
char xx[10]="hello";
return xx;
}
char *fun5(void)//.heap中的地址能返回,可读可写
{
char *p;
p=(char *)malloc(10*sizeof(char));
if (NULL==p)
exit(1);
else
strcpy(p,"你好!");
return p;
}
int main(int argc, char *argv[])
{
char *temp;
printf("%s\n",fun1());
printf("%d\n",*fun2());
printf("%d\n",*fun2());
printf("%d\n",*fun3());
strcpy(temp,fun4());
printf("%s\n",temp);
strcpy(temp,fun5());
printf("%s\n",temp);
free(temp);
return 0;
}
5.函数本身是指针,就是函数指针
C语言规定:函数的名字就是函数的首地址,即函数的入口地址
函数本身也是地址,且该指针指向.text即代码区,在0x08048000地址之后
#include "stdio.h"
int fun(int a,int b)
{
return a+b;
}
int main(int argc, char *argv[])
{
char *str="hello";
int (*p2)(int a,int b)=fun;//函数指针
printf("str=%p\n",str);
printf("p2=%p\n",p2);
return 0;
}
①函数指针定义方法
返回值类型 (*函数指针变量名)(形参表)
int (*p)(int a,int b)
int * (*p)(int * a,int *b);//表示的是定义了一个函数指针p,该函数返回值是int *,形参是两个int *
#include "stdio.h"
int fun(int a,int b)
{
return a+b;
}
int main(int argc, char *argv[])
{
int x=10,y=20,sum;
int (*p)(int a,int b)=fun;//函数指针
sum=fun(x,y);
printf("x=%d,y=%d,sum=%d\n",x,y,sum);
sum=p(x,y);
printf("*****************\n");
printf("x=%d,y=%d,sum=%d\n",x,y,sum);
return 0;
}
②函数指针数组
返回值类型 (*函数指针数组名[数组大小])(形参表)
#include "stdio.h"
int fun(int a,int b)
{
return a+b;
}
int fun2(int a,int b)
{
return a-b;
}
int main(int argc, char *argv[])
{
int x=30,y=20,sum;
int (*p2)(int a,int b)=fun;//函数指针
int (*p[2])(int a,int b)={fun,fun2};//函数指针数组
sum=p[0](x,y);
printf("sum=%d\n",sum);
printf("***********\n");
sum=p[1](x,y);
printf("sum=%d\n",sum);
return 0;
}
③函数指针常用地方
用在给函数传参
即当参数不一样时,根据参数调用不同的函数
#include "stdio.h"
void fun(char *str,int (*p)(int ,int ),int x, int y)
{
printf("四则运算中的%s:",str);
printf("%d与%d的结果是%d\n",x,y,p(x,y));
}
int fun1(int a,int b)
{
return a+b;
}
int fun2(int a,int b)
{
return a-b;
}
int fun3(int a,int b)
{
return a*b;
}
int fun4(int a,int b)
{
return a/b;
}
int main(int argc, char *argv[])
{
int x,y;
scanf("%d %d",&x,&y);
fun("加法运算",fun1,x,y);
fun("减法运算",fun2,x,y);
fun("乘法运算",fun3,x,y);
fun("除法运算",fun4,x,y);
return 0;
}
6.main函数的参数
int main(int argc ,char *argv[])
argc代表参数的个数
argv存放各参数首地址(系统把每个参数当作一个
字符串放在系统缓冲区,把首地址放在指针数组中)
#include "stdio.h"
#include "stdlib.h"
int main(int argc, char *argv[])
{
int i;
for (i=0;i<argc;i++)
{
printf("%s\n",argv[i]);
}
return 0;
}
#include "stdio.h"
#include "stdlib.h"
int fun(int a,int b)
{
return a+b;
}
int fun2(int a,int b)
{
return a-b;
}
int main(int argc, char *argv[])
{
int a=10,b=5;
if (argc<2)
{
printf("缺少参数,请补充参数\n");
printf("+代表加法运算\n");
printf("-代表减法运算\n");
return 0;
}
if (argv[1][0]=='+')
printf("%d+%d=%d\n",a,b,fun(a,b));
else if (argv[1][0]=='-')
printf("%d-%d=%d\n",a,b,fun2(a,b));
else
printf("参数错误,请确认输入的是+或者-\n");
return 0;
}
十一、特殊指针及容易混淆的指针
1.特殊指针
①空类型指针(void *)
char *
int *
float *
void *指向void类型的指针吗???
不是,没有void类型的变量
真实含义是定义了一个指针,但不指定类型
void * memset(void *s,int c,size_t n);
void * malloc(size_t n);
void *类型指针可以指向任何数组类型的变量,但使用时要强制类型转换
#include "stdio.h"
int main(int argc, char *argv[])
{
void *p;
int a=123;
p=&a;
printf("*p=%d",*(int *)p);
char b='B';
p=&b;
printf("*p=%c",*(char *)p);
return 0;
}
②NULL
空指针
char *p=NULL;//将指针变量指向空,即不指向任何的变量
表示将指针变量指向空,即不指向任何的变量
NULL在很多编译器例定义为0,但并不是所有编译器这样
也可以理解为:将p指向内存编号为0x00 00 00 00的存储单位,而0x00 00 00 00地址为保留地址,所以不指向任何变量。
#include "stdio.h"
int main(int argc, char *argv[])
{
char *p;//char *p=NULL;避免使用野指针
printf("*p=%d",*p);//使用了野指针
char b='B';
p=&b;
printf("*p=%c",*p);
return 0;
}
对比:
#include "stdio.h"
int main(int argc, char *argv[])
{
char *p=NULL;
if (NULL!=p)
printf("*p=%d",*p);//使用了野指针
char b='B';
p=&b;
if (NULL!=p)
printf("*p=%c",*p);
return 0;
}
③容易混淆的指针
int *a[10]//指针数组,表示是一个含有10个指针变量的数组
int (*a)[10]//数组指针,表示是一个指针,该指针指向一个含有10个整型变量的数组
int **p;//二级指针,该指针指向一个指针
用法一:
int *q;//一级指针,该指针指向一个普通变量
p=&q;
用法二:
int *q[10];
p=q;//取得指针数组的首地址
p=&q[0];//取得指针数组的首地址
#include "stdio.h"
int main(int argc, char *argv[])
{
char **p=NULL;
char *q[3]={"hello","world","您好"};
p=&q[0];//p=q;
int i;
for (i=0;i<3;i++)
printf("q[%d]=%s",i,*(p++));
return 0;
}
int *f(void);//表示是一个函数的声明,该函数返回值是int *
int (*f)(void);//表示的是一个函数指针,该指针指向一个返回值为int型无形参的函数,
十二、动态内存使用
1.1特性
在堆(heap)里面,空间大,并且可以动态申请,不是固定的,相对效率低。
它的使用是通过地址访问的,使用完一定要释放。
涉及函数,malloc free memset calloc
1.2何为动态分配
相对于静态分配
静态分配:在程序运行前,编译时事先分配大小,int a[20],使用是必须事先知道大小,分配在栈区、bss、data、rodata,必须按计划分配
动态分配:在程序运行过程中,根据需要动态申请,自由分配所需空间,按需分配,在堆(heap)区。
1.3动态分配函数
1、malloc函数
#include "stdlib.h"
函数原型:void * malloc(size_t size)
返回值:成功返回分配空间的首地址
失败返回空指针
注意:使用该函数时,要判断是否分配成功
#include "stdio.h"
#include "stdlib.h"
int main(int argc, char *argv[])
{
char *ptr=NULL;
int num;
printf("请输入你想要开辟的空间大小\n");
scanf("%d",&num);
ptr=(char *)malloc(num*sizeof(char));
if (NULL==ptr)
{
printf("动态申请失败!\n");
return 0;
}
printf("请输入不超过%d大小的字符串\n",num);
scanf("%s",ptr);
printf("您输入的字符串是:%s",ptr);
free(ptr);
return 0;
}
2.free函数
#include "stdlib.h"
函数原型:void free(void *ptr)
使用:
ptr=(char *)malloc(num*sizeof(char));
free(ptr);
注意:free ptr,原先ptr所指向的空间就被回收,这块空间就不能使用了,ptr就成了野指针,一块空间只能free一次,多次free会发生意外的情况
3calloc函数
#include "stdlib.h"
函数原型:void *alloc(size_t nmemb,size_t size)
size_t是一个无符号整形,在头文件里用typedef定义的
返回值:成功返回分配空间的首地址
失败返回空指针
与malloc的区别
①名字不一样
②参数个数不一样
③malloc是开一块空间,alloc是开nmemb块连续的空间
④malloc申请的空间内容是随机的,而alloc开辟的空间内容是确定的就是0
#include "stdio.h"
#include "stdlib.h"
int main(int argc, char *argv[])
{
int *ptr=NULL,*ptr2=NULL,*ptr3;
int num=10,i;
ptr3=(int *)malloc(10*num*sizeof(int));
if (NULL==ptr3)
{
printf("动态申请失败!\n");
return 0;
}
for(i=0;i<10*num;i++)
ptr3[i]=i;
free(ptr3);
ptr=(int *)malloc(num*sizeof(int));
if (NULL==ptr)
{
printf("动态申请失败!\n");
return 0;
}
for(i=0;i<10;i++)
printf("%d ",ptr[i]);
printf("****************\n");
ptr2=(int *)calloc(num,sizeof(int));
if (NULL==ptr2)
{
printf("动态申请失败!\n");
return 0;
}
for(i=0;i<10;i++)
printf("%d ",*(ptr2+i));
free(ptr);
free(ptr2);
return 0;
}
4.realloc
#include <stdlib.h>
函数原型:void *realloc( void *ptr, size_t size );
要保证malloc 、alloc空间连续性,所以遵守以下原则:
给ptr重新分配空间,若以前的空间够用,就用以前的空间,首地址不变,内容不变
若以前空间不够用,而后续空间没有被占用,首地址不变,在后续空间增加分配,原地址内容不变
若以前空间不够用,但后续空间被占用,释放以前空间,重新找空间另外分配,首地址改变,但会在释放原空间前将原来的内容复制到新空间
malloc 、calloc、realloc 都是动态申请内存空间,都要不用空间时要用free去释放,否则会内存泄漏。
5.内存泄漏
概念:申请的内存,首地址丢了,找不到了,再也没法使用了,但是也没有释放,这样内存就泄漏了
内存泄漏案例一:
#include "stdio.h"
#include "stdlib.h"
int main(int argc, char *argv[])
{
char *ptr=NULL;
int num=1024;
ptr=(char *)malloc(num*sizeof(char));
if (NULL==ptr)
{
printf("动态申请失败!\n");
return 0;
}
ptr="hello world!";
return 0;
}
内存泄漏案例二:
#include "stdio.h"
#include "stdlib.h"
void fun(void)
{
char *ptr=NULL;
int num;
printf("请输入你想要开辟的空间大小\n");
scanf("%d",&num);
ptr=(char *)malloc(num*sizeof(char));
if (NULL==ptr)
{
printf("动态申请失败!\n");
return 0;
}
scanf("%s",ptr);
}
int main(int argc, char *argv[])
{
fun();
fun();
return 0;
}
解决案例一:
#include "stdio.h"
#include "stdlib.h"
int main(int argc, char *argv[])
{
char *ptr=NULL;
int num=1024;
ptr=(char *)malloc(num*sizeof(char));
if (NULL==ptr)
{
printf("动态申请失败!\n");
return 0;
}
free(ptr);//释放空间
ptr="hello world!";
return 0;
}
解决案例二:
#include "stdio.h"
#include "stdlib.h"
void fun(void)
{
char *ptr=NULL;
int num;
printf("请输入你想要开辟的空间大小\n");
scanf("%d",&num);
ptr=(char *)malloc(num*sizeof(char));
if (NULL==ptr)
{
printf("动态申请失败!\n");
return 0;
}
scanf("%s",ptr);
free(ptr);// 释放内存
}
int main(int argc, char *argv[])
{
fun();
fun();
return 0;
}
在vc下演示内存泄漏的危害:
#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#include "windows.h"
int fun(void)
{
char *ptr=NULL;
int num=1024;
ptr=(char *)malloc(num*sizeof(char));
if (NULL==ptr)
{
printf("动态申请失败!\n");
return 0;
}
return 0;
// free(ptr);// 释放内存
}
int main(int argc, char *argv[])
{
int i;
for (i=0;i<1024;i++)
{
Sleep(200);
fun();
}
return 0;
}
程序设计题(要求用指针的方法完成)
1. 编写程序,将一个字符串反向存放(编写函数实现)。
2. 编写程序my_strlen(char *str),测得指定字符串的长度(编写函数实现)
3. 编写一个字符串拷贝函数,my_strcpy(char *dest,char *src)(编写函数实现)
将源操作数src中的字符串拷贝到dest所指向的数组中
4. 编写一个函数实现将"12345"变成十进制12345(编写函数实现)
5. 编写函数my_strcmp(char *str1, char *str2),比较、返回两等长字符串的大小(编写函数实现)
要求相等返回0,字符串1大于字符串2返回1,字符串2大于字符串1返回-1
字符串1的第一个字母大于字符串2的第一个字母,则判定字符串1大于字符串2,相等则比较第二字母,以此类推,全部相同则判定两字符串相等

