zoukankan      html  css  js  c++  java
  • 二级指针的思考

    最近在群里出现了一道面试提,看着打架讨论挺热烈就开始思考一下这个问题。下边先把题贴出来:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    void Getmemery(char *p)
    {
        p=(char *)malloc(100);
    }
    
    void main()
    {
        char *str=NULL;
    
        Getmemery(str);
        strcpy(str,"hello world");
        printf("%s",str);
        free(str);
    }

    这就是这个道题了,这里边是有个错误的。不知道看出来没有。

    其实要更清楚的搞懂这个问题,我们首先需要了解一个知识点。就是    堆、栈、自由存储区、全局/静态存储区和常量存储区。

    我们在弄懂这个问题之后 看下边一个小例子:

    1 int main () {
    2     char* p= "hello";
    3     *p = "world";
    4     printf("%s",p);
    5     return 0;
    6 } 

    你编译运行之后就会发现错误,这个错误就在于你试图去改变 常量存储区 里边的内容。那我们需要修改的话怎么办?

    int main () {
        char* p= "hello";
        char *str = "world";
        p = str;   //改变地址的指向 
        printf("%s",p);
        return 0;
    } 

    改变它地址的指向,这个就是方法,你如果非要改变常量存储内内容也不是没有方法,这个不属于考虑范围。


    上边的问题理解清楚了我们就这是开始进入下一个话题

    指针数组

    定义: 指针数组中每一个元素都存放一个地址。都当于一个指针变量。 

    示例: int* p[4];   char* type = {"C", "C++", "JAVA", "C#", "Ruby"};

     1 int main() {
     2 
     3     char* type[] = { "C", "C++", "JAVA", "C#", "Ruby" };
     4     int a[] = { 1,2,3,4,5 };
     5     int *num[5];
     6 
     7     for (int n = 0; n < 5; n++) {
     8         printf("%s  ", type[n]);
     9     }
    10 
    11     for (int i = 0; i < 5; i++) {
    12         num[i] = &a[i];
    13     }
    14     printf("
    ");
    15 
    16     for (int j = 0; j < 5; j++) {
    17         printf("%p  ", num[j]);
    18     }
    19     printf("
    ");
    20     for (int k = 0; k < 5; k++) {
    21         printf("%d  ", *num[k]);
    22     }
    23     printf("
    ");
    24 
    25     return 0;
    26 }

               

    在这个例子中我们应该能分清楚 指针数组里边到底存的是什么。 换句话说  int *num = {&a[0], &a[1], &a[2], &a[3], &a[4], &a[5]}


    基本了解指针数组之后,我们做点小的测试看看对于指针的概念怎么样?

     1 void change(char *p);
     2 int main() {
     3     char old[] = { 1,3 ,5 }; 
     4     printf("&old[0] = %p
    ", &old[0]);
     5     printf("&old[1] = %p
    ", &old[1]);
     6     printf("&old[2] = %p
    ", &old[2]);
     7     char *p = old;     // [1] 
     8     change(p);
     9     for (int i = 0; i < 3;i++,p++) {
    10         printf("%d  ", *p);
    11     }
    12     printf("
    ");
    13     return 0;
    14 }
    15 void change(char *p) {
    16     char news[] = {2,4,6};  //[2]
    17     p = news;               //[3]
    18 }
     

     

    结果是 还是  1, 3, 5。 可能某些就会产生疑问了,怎么没有改变。不是使用的地址传递。 我们解释一下这个问题。C不同于C++,参数是通过值传递或者地址传递的,而不是通过引用。也就是说,实际参数  先自己copy一份,然后传递给形式参数 *P接收

    在执行完第一步之后 也就是 7行, P指向old 的都地址。 执行第二步,对值进行拷贝出现P_COPY 指向old,添加新的数组。 第三步,P_COPY 指向new  数组的首地址。 这个过程是P_COPY 指向new   与main()函数里边的 P 没有半毛钱关系。  -- 听到这里可能明白,也可能有点晕,我们下边继续了解。怎么让两个真交换呢?

    void change(char **p);
    int main() {
        char old[] = { 1,3 ,5 }; 
        printf("&old[0] = %p
    ", &old[0]);
        printf("&old[1] = %p
    ", &old[1]);
        printf("&old[2] = %p
    ", &old[2]);
        char *p = old;            // [1] 
        change(&p);             // [2]
        for (int i = 0; i < 3;i++,p++) {
            printf("%d  ", *p);
        }
        printf("
    ");
        return 0;
    }
    void change(char **p) {
        char *pt = NULL;
        static char news[] = {2,4,6};     //[3]  //特别注意哈 static
        *p = news;                        //[4]
    }

     在进行完第二步进行数值的拷贝, P_COPY  = &P;   意味着 *P_COPY 指向 P所在空间, 改变*P_COPY 里边的值 会改变P 里边的值,即最改变最终指向。这里边和上题的区别是我们是用到P这个指针变量的地址,用 P_COPY存储, 使得P_COPY 和 P 产生了关联。  这是和上题最大的区别。

    下边还是一个交换的例子自己体会一下。 

     1 void swap(char **str, char **dest);
     2 int main() {
     3     char *A = "abcd", *B = "efgh";
     4     printf("A = %p, B = %p
    ", A, B);
     5     printf("&A = %p, &B = %p
    ", &A, &B);
     6     swap(&A, &B);
     7 
     8     printf("交换后: A = %p, B = %p
    ", A, B);
     9     printf("交换后: A = %s ,B = %s", A, B);
    10     return 0;
    11 }
    12 void swap(char **str, char **dest) {
    13     char *p = NULL;
    14     printf("str = %p, dest = %p
    ", str, dest);
    15     p = *str;
    16     *str = *dest;
    17     *dest = p;
    18 }

    这是一个交换 的实例, 在C语言中有值传递地址传递, 但是没有引用(c++)中概念。

  • 相关阅读:
    nignx的master进程和worker进程的作用
    JVM运行机制
    ElasticSearch介绍与安装
    Maven打可执行包的pom.xml配置
    pg按日,周,月进行数据统计
    数据库中重复数据查询和删除
    聚类算法的评估应面向具体问题
    将博客搬至CSDN
    Mutual Information
    层次化聚类
  • 原文地址:https://www.cnblogs.com/causal360/p/4796810.html
Copyright © 2011-2022 走看看