问题:char* ptr = malloc(0*sizeof(char));
if(NULL == ptr)
printf("got a NULL pointer");
else
printf("got a Valid pointer");
请问:上面的程序输出为什么?在C99的标准里面解释到,如果给malloc传递0参数,其返回值是依赖于编译器的实现,但是不管返回何值,该指针指向的对象是不可以访问的。在VC6编译环境下,输出“got a Valid pointer”
但是我试图给该指针赋值,如:*ptr = ''a'' ;编译器并没有给出任何错误和警告信息,接着,我再输出该值,printf("*ptr=%d\n",*ptr) ;也可以正常输出。
但是当我用free(ptr) ;释放内存的时候,出现错误,为什么呢?下面是我看了网友经过讨论以后我比较认同的看法:
当malloc分配内存时它除了分配我们指定SIZE的内存块,还会分配额外的内存来存储我们的内存块信息,用于维护该内存块。因此,malloc(0)返回一个合法的指针并指向存储内存块信息的额外内存,我们当然可以在该内存上进行读写操作,但是这样做了会破坏该内存块的维护信息,因此当我们调用free(ptr)时就会出现错误。完整程序如下:
#include
#include
int main()
{
char *ptr ;
ptr = malloc(0*sizeof(char)) ;
if (NULL == ptr)
printf("got a NULL pointer\n");
else
{
printf("got a Valid pointer\n");
*ptr = ''a'
printf("the value at %X is:%c\n",ptr,*ptr);
free(ptr) ;//if we did not add this statement ,the program can run normnlly,or we will get
// a runtime error.
}
return 0 ;
}
既然malloc另外分配内存来维护该内存块,也就是说分配来用于维护该内存块的内存的大小也是有限的,那么到底是多少呢?这和可能也依赖于实现,在VC6下,是56BYTE,下面是测试程序:
#include
#include
#include
int main()
{
char *ptr ;
ptr = malloc(0*sizeof(char)) ;
if (NULL == ptr)
printf("got a NULL pointer\n");
else
{
printf("got a Valid pointer\n");
// 有56个a,另外有一个字节用于保存''\0'
strcpy(ptr,"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
//printf("the value at %X is:%c\n",ptr,*ptr);
printf("the string at %x is :%s\n",ptr, ptr);
// free(ptr);
}
return 0 ;
}
此时我们没有把free(ptr)编译进来,同样会发生异常,程序输出很多个56个a,我暂时还不明白为什么?????如果把free(ptr);编译进来,就会发生运行错误!
通过上面的讨论和程序的验证,确实证明了网友和我的想法是正确的,也就是malloc(0)还会额外分配一部分空间(在VC6下是56字节)用于维护内存块。
兄弟们可以运行下上面的程序,愿意的话帮我把为什么输出很多个56个a出来这个问题解决掉!
找工作要面试,所以在这最难就业季,很多人对面试题特别感兴趣,津津有味地研究,孜孜不倦地学习。
但实际上这些面试题目良莠不齐,许多题目根本上就是垃圾和毒药。
比如问“空结构体”的尺寸是多少,实际上C语言中根本就没有“空结构体”,因为结构体的定义本身就规定结构体不可以为空。所以,“空结构体”的尺寸是多少这样的问题是驴唇不对马嘴的伪问题。
有些题目喜欢转牛角尖,比如问调用
malloc(0)
得到的返回值是否是NULL?(http://www.cnblogs.com/wuyuegb2312/p/3219659.html)
这在实践中是基本没用的知识。
尽管没用,但问题本身还是成立的。可笑的是给出的解答是错的,解答竟然说malloc(0)返回的一定不是NULL。
实际上malloc(0)的返回值可能是NULL也可能不是NULL,和实参为一个正整数时没什么区别。如果返回值不为NULL,也应该用free()函数释放。malloc(0)唯一不同的地方就是,就算你申请内存成功,即malloc(0)返回值不为NULL,你也没法使用这块内存。
有一些考察编程能力的题目,则直接暴露出了出题者的编程能力很差。比如
两个单链表(singly linked list),每一个节点里面一个0-9的数字,输入就相当于两个大数了。然后返回这两个数的和(一个新list)。这两个输入的list长度相等。 要求是:1. 不用递归。2. 要求算法在最好的情况下,只遍历两个list一次 ,最差的情况下两遍。(链表存储数据为从低位到高位)
这个题目就很搞笑。因为只要小学毕业,就知道多位数加法只需要从低位到高位遍历一次就可以了,遍历两次说明小学没毕业。非但只需要一次,同样不需要两个加数位数相同。计算和这个过程既然能在纸上用笔完成,那么用代码同样也能够完成。
那么,题目为什么给出“两个输入的list长度相等”这样没用的条件以及“最差的情况下两遍”这样笨拙的要求呢?只能解释为出题者自己不会用代码处理两个list长度不相等的情况,并且写不出遍历一次的代码。
实际这个问题一点也不难,会写链表的人都能轻易写出两个list不等长,且两链表只遍历一次求和的代码。
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
typedef
struct bignum
{
char dig ;
struct bignum * next ;
}
* LIST ;
LIST get_num( void );
void my_malloc( LIST * );
void output( LIST );
LIST add( LIST ,LIST );
void my_free( LIST );
void move( LIST * );
int get_dig( LIST );
void put( int , LIST * );
int main( void )
{
LIST p_num1 , p_num2 ;
LIST p_sum ;
puts("输入一个整数:");
p_num1 = get_num();
puts("输入一个整数:");
p_num2 = get_num();
p_sum = add( p_num1 ,p_num2 );
output(p_sum);
putchar('\n');
my_free(p_sum);
my_free(p_num1);
my_free(p_num2);
return 0;
}
void my_malloc( LIST * p )
{
if ( ( * p = malloc( sizeof ( * * p ) )) == NULL )
exit(1);
}
//输入,建立从低位到高位的链表
LIST get_num( void )
{
LIST p = NULL ;
int c ;
while ( ( c = getchar() ) && isdigit( c ) )
{
LIST tmp ;
my_malloc ( &tmp );
tmp -> dig = c - '0';
tmp ->next = p ;
p = tmp ;
}
return p;
}
void my_free( LIST p )
{
if ( p->next != NULL )
free( p->next );
free( p );
}
int get_dig( LIST p )
{
if ( p == NULL )
return 0;
return p ->dig ;
}
void move( LIST * pp )
{
if ( *pp == NULL )
return ;
*pp = (*pp) -> next ;
}
void put( int n , LIST * pp )
{
my_malloc( pp );
(*pp)->dig = n ;
(*pp)->next= NULL;
}
LIST add( LIST p1 ,LIST p2 )
{
LIST p_res = NULL ;
LIST * pp_res = & p_res ;
char low , high = 0 ;
while ( p1 != NULL || p2 != NULL )
{
low = high ; //high为前一次的进位
low += get_dig( p1 ) + get_dig( p2 ) ;
high = low / 10 ; //记下进位
low %= 10 ;
put( low , pp_res ); //将和放入新结点
pp_res = & (*pp_res)->next ;
move( &p1 ) , move( &p2 ) ;
}
if ( high != 0 ) //处理最高位的进位
put( high , pp_res );
return p_res;
}
void output( LIST p )
{
if ( p->next != NULL )
output( p->next );
putchar( p -> dig + '0' );
}
写到这里,我很想说,有些面试官根本就是南郭先生滥竽充数,有些面试题的解答者也如是。但为了避免因为把“想”的东西说出来遭到刑拘,我还是说有些面试官不是南郭先生滥竽充数好了。
至于是否把南郭先生们出的面试题及垃圾解答当回事,您自己看着办好了。