C语言指针基础getmemery几个经典问题

在中职学校当一名C语言教师。

在学习C语言指针的时候,为了给学生巩固指针知识,总结了几个C语言指针容易出错的地方。

程序示例 一、

#include <stdio.h>
char*getmemery()
{
    char p[]="Hello,World!";
    return p;
}
int main()
{
    char*str=NULL;
    str=getmemery();
    printf("%s\n",str);
    return 0;
}

 getmemery()函数中,p[ ]是在函数中申请的数组,是临时变量,在函数返回时,指针p所指向的数组内存块会被释放掉,main函数能得到p的指针地址,但是这个指针所指向的内存块已经被释放掉了,所以printf打印指向这个地址,输出不了任何内容,或者是乱码。

程序示例 二、

#include <stdio.h>
char *getmemery()
{
    char *p = "Hello,World!";
    return p;
}
int main()
{
    char *str = NULL;
    str = getmemery();
    printf("%s\n",str);
    return 0;
}

该程序和示例一的差不多,就只是把数组p改成了,指针p,这里指针p指向的是一个字符串常量,而字符串常量,程序编译的寿,就已经确定在程序中的了,字符串常量的生存周期跟整个程序的生存周期一致,需程序结束,该字符串常量的内存块才会被释放,所以这个程序,str接收到返回的指针所指向的内存块没有没释放,所以该程序正常输出:Hello,World!

程序示例 三、

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
void getmemery(char *p) 
{ 
    p = (char *)malloc(100); 
}
 
int main() 
{ 
    char *str = NULL; 
    getmemery(str); 
    strcpy(str,"Hello,World!"); 
    printf("%s\n",str);
    if(str)free(str);
    str = NULL;
    return 0;
}

该程序使用malloc动态申请内存,很多同学想,这个函数的参数是*p,传的是地址,所以能改变原函数中的值。

但请仔细想想,我们在使用传指针的时候,是怎样改变原函数中的值的呢,请看示例

#include <stdio.h>
void fun(int *p){
    *p = 8;         //要使用指针改变mian中a的值,这里需要使用(*p)来整体操作。
}
int main(int argc, char const *argv[])
{
    int a = 10;
    int *p = &a;
    fun(p);
    printf("a = %d\n",a);       //这里输出的是a = 8;
    return 0;
}

所以,要想在函数中改变原调用函数中的值,必须使用*p整体操作才可以,若只使用指针p则会是指形参中的指针p指向别的地方而已。对函数外的值没有改变。str中的值依然还是NULL没有改变,程序执行报错。

根据这个,则示例三中的程序应该使用*p = malloc,那么参数就应该使用**p,二级指针。请看示例4。

程序示例 四、

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
void getmemery(char **p)
{  
    *p = (char *)malloc(100);
}  
int main()
{  
    char *str = NULL;  
    getmemery(&str);  
    strcpy(str,"Hello,World!");  
    printf("%s\n",str);
    if(str)free(str);
    str = NULL;
    return 0;
} 

这样子就能正确的运行,正确输出结果。为什么呢。

举例子:

int a,*p = &a,则使用*p能改变a的值。对把,

那么对于*str呢,**p = &str,则通过*p就能改变 *str中的值。甚至可以类推至三级指针。

所以通过*p改变main函数中str指针所指向的值,让str指向在函数中申请的内存块首地址。函数结束,malloc中申请的内存不会释放,所以能正常输出结果。

程序示例 五、

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
char *getmemery(int num)  
{  
    char *p = (char *)malloc(sizeof(char) * num);  
    return p;  
}   
int main()
{  
    char *str = NULL;  
    str = getmemery(100);   
    strcpy(str, "Hello,World!");  
    printf("%s\n",str); 
    if(str)free(str);
    str = NULL;
    return 0;
} 

该程序采用指针函数的方式实现获取内存。直接将动态申请的内存块的首地址通过指针p返回给mian函数,所以str接收到的就是申请的内存块地址,能正常输出。

程序示例 六、

#include <stdio.h> 
char *getmemery(void)  
{   
    return "Hello,World";  
}  
int main()  
{  
    char *str = NULL;  
    str = getmemery();   
    printf("%s\n",str);   
}  

改程序和例题2类似,直接返回的是常量字符串的指针。常量字符串,跟程序运行周期一致,所以能正常输出。

只是该程序在低版本的编译器中能正常运行,但在Visual Studio2019中,我测试,会有错误,常量字符串的指针是 const 类型。

所以会出现类型不匹配的情况。增加函数const类型,可以解决问题。

程序示例 七、

#include <stdio.h> 
int main()   
{  
    char *str = (char *) malloc(100);  
    strcpy(str, "Hello,World!");  
    free(str);        
    if(str != NULL)  
    {  
      strcpy(str, "Hello,World!");  
      printf(str);
     }  
}

该程序考察动态申请内存释放问题。

经过free(str) str所指向的内存块已经被释放,但是指针还在,我还是指向那个地方,只是那个地方已经被释放了,什么也没有,但str还是傻傻的指向那。好比,我手指着个房子,但那个房子如今已经被拆了,但我还是指着那个地方。

所以,这种现象就成为野指针。

在判断str的时候,str依然不是空,所以能通过程序中的if结构,只是不能再往里面复制东西了。就是房子已经被拆了,还能把东西放到房子的五楼吗?所以在释放内存后,就要把str指向NULL。消除野指针带来的危害。

程序实例 八、

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
int main()   
{  
    char *str=(char *)malloc(100);  
    strcpy(str, "Hello,World!");  
    str+=6;  
    free(str);  
    if(str!=NULL)  
    {  
        strcpy(str, "Hello,World!");  
        printf(str);  
    }  
} 

这种情况,申请也是不行的,运行会报错而终止运行。str是申请内存的地址,而将str后移,想着只释放后面的内存块,这样的操作是不允许的,具体原因,我猜测是系统会记录申请内存的地址,如果释放的不是系统记录的地址,释放就会出错,也有可能只能通过内存块的首地址来释放。具体的若有知道的,可以留言告诉我。我只是测试了,是不行的。

好了,这就是我为我班上的同学总结的指针的问题。和我的讲解。若有错误的地方,请留言指正。谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值