C语言 malloc()函数 分配内存空间尺寸的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言 malloc()函数 分配内存空间尺寸的问题相关的知识,希望对你有一定的参考价值。

char *c = (char*)malloc(0);
scanf("%s",c);
printf("%s",c);

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

input:
1234567

output:
1234567
----------------------------------
我只申请了尺寸为0的内存空间,却写入了7个字符,是不是已经修改到了不该修改的内存

应该怎样合理使用malloc()函数?
感谢各位的耐心解答,谢谢!

这个问题首先得从堆栈说起,一个程序一般分为三段:代码段,数据段(静态数据),和堆栈段。堆栈段存储程序中的变量、程序传递的参数等(动态分配的变量存储在堆中,静态分配的存储在栈中)。堆栈的增长方式如下:

程序在运行的时候会预先分配堆栈空间,所以你的问题中不一定修改了不该修改的地方,有可能那里本来就是空的。


再回到malloc这个函数上来,malloc主要负责分配空间,返回该空间的首地址。那为什么申请空间为0,却可以存储7个字符呢?那是因为C语言的指针中并不检查数组的越界问题,不信的话,你可以这样:char ch[5],然后你去读写ch[6](printf或scanf),这样是不会报错的。但是我们在使用的时候,千万别越界使用,因为这样的程序是非常危险的,试想,如果越界使用的地址正好是一个操作系统的地址,那么你一修改,系统就崩了。同时,C语言的这个机制被黑客广泛地应用与缓冲区溢出攻击,所以你非但不能越界使用指针,还得时刻考虑到指针(数组)是否越界,以加强程序的安全性。


希望对你有所帮助。。。

追问

一般怎么来防止越界的问题呢?比如我这里使用 scanf()函数,写代码的时候我不知道运行的时候用户会输入多少字符..
感谢用心~

追答

这个比较简单的方法就是用一个缓冲数组,然后对这个数组进行检测。这个在安全编程中经常用,但是程序效率会有所降低。
比如:char str[100],tmpstr[100]。然后输入到tmpstr中,经检测是否越界后,再赋值给str,这样就可以避免直接使用地址,在对str读写时不会出错。
当然,话又说回来,在刚学习的阶段不用考虑这些问题,否则程序的复杂程度会大大增加,不利于学习,但是在做项目时要有这个意识。

参考技术A C语言中malloc是动态内存分配函数。
函数原型:void *malloc(unsigned int num_bytes);
参数:num_bytes 是无符号整型,用于表示分配的字节数。
返回值:如果分配成功则返回指向被分配内存的指针(此存储区中的初始值不确定),否则返回空指针NULL。void* 表示未确定类型的指针,void *可以指向任何类型的数据,更明确的说是指申请内存空间时还不知道用户是用这段空间来存储什么类型的数据(比如是char还是int或者...)
功能:分配长度为num_bytes字节的内存块
注意:当内存不再使用时,应使用free()函数将内存块释放。函数返回的指针一定要适当对齐,使其可以用于任何数据对象。关于该函数的原型,在以前malloc返回的是char型指针,新的ANSIC标准规定,该函数返回为void型指针,因此必要时要进行类型转换。
实例:
#include"stdio.h"

#include"malloc.h"//malloc()函数被包含在malloc.h里面

int main(void)


char*a=NULL;//声明一个指向a的char*类型的指针

a=(char*)malloc(100*sizeof(char));//使用malloc分配内存的首地址,然后赋值给a

if(!a)//如果malloc失败,可以得到一些log


perror("malloc");
return-1;


sprintf(a,"%s","HelloWorld\n");//"HelloWorld\n"写入a指向的地址

printf("%s\n",a);//输出用户输入的数据

free(a);//释放掉使用的内存地址

return0;

参考技术B malloc是给指针变量分配内存空间的函数命令
正确使用:
分配的空间要能保证容下你想存储的数据,不要和机器逗着玩(分配0空间,或少于自己实际需要的空间),如你上面的操作,表面上你程序运行没有问题,可实际上你占用了别人的地盘,只是当前你很幸运没有使程序出现问题,但不保证一定不出问题!!

不再使用的指针,一定要free()来释放空间!malloc 与free要配对使用,即:有malloc必要有free追问

可是... 使用scanf(),我怎么能知道程序运行的时候,用户会输入多少字符?那这时应该怎样确定分配多大内存?

追答

这个在应用程序设计时会限制用户输入的有效数据的长度的!
在真正的程序设计时,我们很少会用scanf()函数来进行数据输入,会采用相应的有效代码(因开发系统情况而异) malloc函数只是动态分配内存的一个命令,学者只需要知道它的用法就好了,具体情况要具体分析进而确定程序实现方式。

本回答被提问者和网友采纳
参考技术C

你何必纠结一定要分配用户输入字符数量长度的空间呢?开一个足够大的数组不就得了?

如果你一定要malloc准确的大小,你可以

char *c;
char *s=malloc(100000*sizeof(char));//malloc一个足够大的数组,暂时储存输入
scanf("%s",s);
c=(char*)malloc(strlen(s)*sizeof(char));
strcpy(c,s);
free(s);//输入结束后把输入储存,再把这个大数组释放

内存分配函数(C语言)

C 标准函数库提供了许多函数来实现对堆上内存管理
malloc函数:malloc函数可以从堆上获得指定字节的内存空间(必须初始化)
free函数:释放内存,防止内存泄露
calloc函数:与 malloc类似,但不需要初始化
realloc函数:重新分配内存

头文件stdlib.h

malloc

malloc函数可以从堆上获得指定字节的内存空间,其函数原型如下:

void * malloc(int n)

其中,形参n为要求分配的字节数。如果函数执行成功,malloc返回获得内存空间的首地址;如果函数执行失败,那么返回值为NULL。由于malloc函数值的类型为void型指针,因此,可以将其值类型转换后赋给任意类型指针,这样就可以通过操作该类型指针来操作从堆上获得的内存空间。

需要注意的是,malloc函数分配得到的内存空间是未初始化的。因此,一般在使用该内存空间时,要调用另一个函数memset来将其初始化为全0。memset函数的声明如下:
void * memset (void * p,int c,int n)
该函数可以将指定的内存空间按字节单位置为指定的字符c。其中,p为要清零的内存空间的首地址,c为要设定的值,n为被操作的内存空间的字节长度。如果要用memset清0,变量c实参要为0。malloc函数和memset函数的操作语句一般如下:

int * p=NULL;
p=(int *)malloc(sizeof(int));
if(p==NULL)
    printf("Can't get memory!\\n");
memset(p,0,siezeof(int));

通过malloc函数得到的堆内存必须使用memset函数来初始化

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() 

     int * p=NULL;
     p=(int *)malloc(sizeof(int));
     if(NULL==p)
         printf("Can't get memory!\\n");
         return -1;
     

     printf("%d\\n",*p);           //输出分配的空间上的值
     memset(p,0,sizeof(int));     //将p指向的空间清0
     printf("%d\\n",*p);           //输出调用memset函数后的结果

     *p=2;
     printf("%d\\n",*p);
     return 0;

free函数

从堆上获得的内存空间在程序结束以后,系统不会将其自动释放,需要程序员来自己管理。一个程序结束时,必须保证所有从堆上获得的内存空间已被安全释放,否则,会导致内存泄露。例如上面的demo就会发生内存泄露。

free函数可以实现释放内存的功能。其函数声明为:

void free (void * p)

由于形参为void指针,free函数可以接受任意类型的指针实参。但是,free函数只是释放指针指向的内容,而该指针仍然指向原来指向的地方,此时,指针为野指针,如果此时操作该指针会导致不可预期的错误。安全做法是:在使用free函数释放指针指向的空间之后,将指针的值置为NULL。因此,对于上面的demo,需要在return语句前加入以下两行语句:

free(p);
p=NULL;

calloc函数

calloc函数的功能与malloc函数的功能相似,都是从堆分配内存。其函数声明如下:

void *calloc(int n,int size)

函数返回值为void型指针。如果执行成功,函数从堆上获得size X n的字节空间,并返回该空间的首地址。如果执行失败,函数返回NULL。该函数与malloc函数的一个显著不同时是,calloc函数得到的内存空间是经过初始化的,其内容全为0。calloc函数适合为数组申请空间,可以将size设置为数组元素的空间长度,将n设置为数组的容量。

#include <stdio.h>
#include <stdlib.h>
#define SIZE 5

int main() 
     int * p=NULL;
     int i=0;
     //为p从堆上分配SIZE个int型空间
     p=(int *)calloc(SIZE,sizeof(int));
    if(NULL==p)
         printf("Error in calloc.\\n");
         return -1;
     

     //为p指向的SIZE个int型空间赋值
     for(i=0;i<SIZE;i++)
         p[i]=i;
     //输出各个空间的值
     for(i=0;i<SIZE;i++)
         printf("p[%d]=%d\\n",i,p[i]);
     free(p);
     p=NULL;
     return 0;

realloc函数

realloc函数的功能比malloc函数和calloc函数的功能更为丰富,可以实现内存分配和内存释放的功能,其函数声明如下:

void * realloc(void * p,int n)

其中,指针p必须为指向堆内存空间的指针,即由malloc函数、calloc函数或realloc函数分配空间的指针。realloc函数将指针p指向的内存块的大小改变为n字节。如果n小于或等于p之前指向的空间大小,那么。保持原有状态不变。如果n大于原来p之前指向的空间大小,那么,系统将重新为p从堆上分配一块大小为n的内存空间,同时,将原来指向空间的内容依次复制到新的内存空间上,p之前指向的空间被释放。relloc函数分配的空间也是未初始化的。

注意:使用malloc函数,calloc函数和realloc函数分配的内存空间都要使用free函数或指针参数为NULL的realloc函数来释放。

#include <stdio.h>
#include <stdlib.h>

int main() 
     int * p=NULL;
     p=(int *)malloc(sizeof(int));
     *p=3;
     printf("p=%p\\n",p);
     printf("*p=%d\\n",*p);
     p=(int *)realloc(p,sizeof(int));
     printf("p=%p\\n",p);
     printf("*p=%d\\n",*p);

     p=(int *)realloc(p,3*sizeof(int));
     printf("p=%p\\n",p);
     printf("*p=%d",*p);
    //释放p指向的空间
     realloc(p,0);
     p=NULL;

     return 0;

转自:http://github.thinkingbar.com/allocate-memroy/

以上是关于C语言 malloc()函数 分配内存空间尺寸的问题的主要内容,如果未能解决你的问题,请参考以下文章

c语言中malloc是啥?怎么用?

怎么查看动态分配内存空间的大小(c语言)。

c语言中啥是动态分配内存?

C语言动态数据结构

C语言中的malloc函数的使用?

内存分配函数(C语言)