用指针实现动态数组的功能

首先来介绍一个动态输入,计算平均分的例子

#include<stdio.h>
#include<stdlib.h>
int main()
{
    int *p=NULL;//指针初始化的问题
    int n,i,sum;
    printf("please enter array size:");//请输入学生人数
    scanf("%d",&n);
    p=(int *)malloc(n*sizeof(int));//申请n个sizeof个字节的存储空间,也叫做内存吧,注意这个强制类型转化符号
    if(p==NULL)
    {
        printf("No enough memory \n");
        exit(0);
    }
    printf("please enter the score");
    for(i=0;i<n;i++)//输入n个学生的分数
    {
        scanf("%d",p+i);
    }
    sum=0;//这个就是把分数和的变量初始化为0
    for(i=0;i<n;i++)
    {
        sum=sum+*(p+i);//计算总分,i代表相对于起始位置P的偏移量
    }
    printf("aver=%d\n",sum/n);//输出平均分
    free(p);//释放用malloc()申请的内存
    return 0;
}

空指针(NULL)指向任意的数据类型,为了解决传统数组在限定长度时,存储空间浪费与缓冲区溢出的问题。借助指针的指向性,根据实际需要,确定程序需要分配的内存空间大小。
标准探空操作的意义

   p=(int *)malloc(n*sizeof(int));//申请n个sizeof个字节的存储空间,也叫做内存吧,注意这个强制类型转化符号
    if(p==NULL)
    {
        printf("No enough memory \n");
        exit(0);
    }

内存中可供实际应用的空间很小,动态分配内存后,检查malloc的返回值不是NULL就很有必要了,空指针意味着任意的指向,也认为着没有任何指向,会导致程序崩溃的后果。
可以类比所谓的string.h头文件中包含strcat,strlen,strcpy,strcmp字符串处理函数,而stdlib.h头文件中也包含malloc,free,calloc,realloc四个空间分配函数,再想一下,C语言中头文件的威力是无穷的,呵呵了。
1.malloc的使用
分配若干个字节的空间,返回一个指向该区域的指针。若系统不能提供足够大的内存空间,或者初始的指向不明确,那就铁定返回NULL,当然了,设计指针问题错的太离谱了,直接弹出黄框框警告。
malloc()的原型为:
void malloc(unsigned int size),size表示向系统申请的空间大小,调用成功将返回一个指向void类型的指针void,常用来作为一个万金油指针,和函数里面求导类似,不管会不会,首先去求导。
指针本质是一个被存储着的地址,过去讲过内存中划分为了若干个区域,各种数据类型的值都可以分一块上去,这个区域近似于无限大,说这句话,就是要把所谓的short,int,char看作不同类型的地址,类似于不同的学区,其依托的划片学校不同。
废话这么多,还是要体会到,同种类型的指针才能彼此赋值。如果要调用malloc的返回值赋值给某个指针,应该先根据该指针的基类型,采用一种叫做强制类型转换的方式,将malloc返回的类型不明确指针,强制转化为所需要的类型。
举个例子来说明一下吧:

 int *p=NULL;
    scanf("%d",&n);
    p=(int *)malloc(n*sizeof(int));//申请n个sizeof个字节的存储空间,也叫做内存吧,注意这个强制类型转化符号

讲解一下,malloc(n*sizeof(int)),表示申请n个sizeof个字节的内存,其返回值经过强制类型转换后再赋值给指针变量P,注意这个大写NULL,是在stdio.h中挂过号的,是一个默认的初始化方式。
p=(int )malloc(nsizeof(int)),这个语句执行后,表示一个指向int数据的变量P指向这段存储空间的首地址。
使用这种方式,而非p=(int *)malloc(一个具体值),主要是各种计算机,乃至于各种编译器上,关于各种数据类型所占存储空间的问题,着实是五花八门,记忆复杂。p=(int *****)malloc(n ***** sizeof(int)),先用sizeof计算出本系统中所占内存空间的字节数,再用malloc向系统申请出具体的存储空间,使用这种方法提高了程序的可移植性,意味着不同的数据系统,可以使用同一套代码。
指针 偏移量表示法的应用

for(i=0;i<n;i++)//输入n个学生的分数
    {
        scanf("%d",p+i);
    }

p已经指向一维动态数组的起始地址(数组名),况且i代表相对于这个起始地址的偏移量,p+i代表一维动态数组中第i个元素的地址值,近似可以看作是一种地址间的运算处理方式
(p+i)代表被解引用出来的第i个元素的值
指针 下标表示法的应用
数组是显性的指针,指针是隐形的数组,二者都是C语言中强大的武器,p+i也可是&p[i],引用
*(p+i)表示为p[i]

#include<stdio.h>
#include<stdlib.h>
int main()
{
    int n,*p,sum;
    int i;
    scanf("%d",&n);
    p=(int *)malloc(sizeof(int));
    for(i=0;i<n;i++)
    {
        scanf("%d",p+i);

    }
    for(i=0;i<n;i++)
    {
        sum=sum+*(p+i);
    }
    printf("aver=%d\n",sum);
    free(p);
    return 0;
}

2.free的使用
free:释放malloc分配的存储空间,原型为 void free(void *p),该函数的功能是是释放动态申请的由指针P指向的存储空间,该函数无返回值。free()中参数给出的地址是函数malloc申请空间时候返回的地址,free执行后,以前分配的由指针P指向的内存被清空。
p=(int *)malloc(sizeof(int));
free§;
比方说这个组合就是一对的数值,成对出现,按照百度的解释,free让动态数据内存结构变的真的可以动态,否则就是个伪动态,只能申请,不能释放。
标准库中malloc函数的实现原理。要了解针对malloc的内存存储结构,malloc不像全局变量一样,不是在编译器编译的时候就会分配内存空间,而是在调用到malloc函数时才会分配空间。有时还会中途调用free函数释放空间出来。
malloc是从堆区申请空间,函数结束后不会自动释放,如果不人为地释放的话,要等到程序结束后,系统才会自动回收
malloc用于向系统申请一定数量的内存,如果你的程序一味的申请内存供自己使用,那么系统可分配给其它程序的内存就会减少,到最后无内存可用,最终导致系统运行缓慢,不稳定等问题。显然,这种只索取不奉献的行为是不可取的因此,C语言提供了free函数,用于向系统返还借用的内存。有借有还,再借不难。
3.calloc
用于给若干个同类项分配连续的存储空间,类似于一次性申请n个,调用函数calloc所申请的内存单元,优越的地方是系统会将其自动初置为0.
原型为void *calloc(unsigned int num,unsigned int size),第一个参数num表示向系统申请内存空间的数量,第二个参数size表示需要申请空间的字节数。调用类似于malloc,初始指向不明确,返回NULL;调用成功,返回一个void类型连续存储空间的首地址。
例如:
float *pf=NULL;
pf=(float )calloc(10,sizeof(float);
表示系统申请十个连续的float类型的存储单元,并用指针pf指向该存储单元的首地址,存储单元字节数10
sizeof(float),显然类似于一个数组被申请出来了,第一个参数是数组的长度,第二个参数决定数组元素的类型,函数的返回值是数组的首地址,也就是函数名。
4.realloc
函数realloc用于改变原来分配的内存空间大小,原型为
void *realloc(void *p,insigned int size)。因为由动态分配内存得到的存储单元没有名字,所以只能用指针来引用,一旦改变了指针的指向,也就是丢掉了和数据之间的联系,从而会引发内存泄露的问题
实例,用二维动态数组实现成绩输入与排序的问题。

#include<stdio.h>
#include<stdlib.h>
int FindMax(int *p,int m,int n,int *pRow,int *pCol);
int main()
{
    int *pScore=NULL,i,j,m,n,maxScore,row,col;
    printf("Please enter array size m,n");
    scanf("%d %d",&m,&n);
    pScore=(int *)calloc(m*n,sizeof(int));
   //申请m*n个sizeof个字节的内存,而后进行探空操作
    if(pScore==NULL)
    {
        printf("No enough memory");
        exit(0);
    }
    printf("Please enter the score :\n");
    //二维循环,把M*N个学生的某门课成绩全部输入
    for(i=0;i<m;i++)
    {
        for(j=0;j<n;j++)
        {
            scanf("%d",&pScore[i*n+j]);
        }

    }
    maxScore=FindMax(pScore,m,n,&row,&col);
    printf("maxScore=%d,class=%d,number=%d\n",maxScore,row+1,col+1);
    //输出最高分,最高分所在的班级,最高分的学号
    free(pScore);//释放calloc申请的内存空间
    return 0;
}
//采用打擂的方式排序显然比较容易一些
int FindMax(int *p,int m,int n,int *pRow,int *pCol)
{
    int i,j,max;
    max=p[0];
    *pRow=0;
    *pCol=0;
    for(i=0;i<m;i++)
    //而后再将第零个班的最高分依次和后续比较
    {
        for(j=0;j<n;j++)
        这个循环能依次比较出一个班中的最高分
        {
            if(p[i*n+j]>max)
            *pRow=i;
            *pCol=j;
        }

    }
    return max;//返回数组元素的最大值,m代表行下标值,n代表列下标值,二维数组中存储的元素代表一个确切的分数,这就很类似一个矩阵了,返回矩阵中的一个元素,输出其定位的坐标。
}

  • 5
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

「已注销」

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

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

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

打赏作者

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

抵扣说明:

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

余额充值