【问题标题】:Why 2 stars when passing pointer to a string to a function将指向字符串的指针传递给函数时为什么要打 2 星
【发布时间】:2015-02-16 13:11:26
【问题描述】:

花了很长时间使这段代码工作之后,有人可以向我解释为什么当我将指向字符串的指针作为参数传递给函数时需要 2 星吗? 根据定义,指针将地址保存到将放置某个变量的内存中。所以它是一个有自己地址的变量,在这个地址下是另一个变量的地址。好的。因此,如果我将指针传递给函数,我会使用 & 符号,因为我必须将指针地址传递给函数。美好的。 但接下来会发生什么。该函数接收该指针在内存中的位置信息。好的。这是我的理解。我不明白为什么在定义函数及其参数时需要两颗星。我正在传递一个指向 char 变量的指针。为什么不 void wpisuj(char * w)。为什么是 wpisuj(char** w)。 内存分配对我来说是可以理解的——我用 malloc 保留了内存,而 malloc 返回了这个内存的地址,所以我把这个地址作为变量 w 的值。 还有一些我不明白的事情,如果 *w 是指针并将新创建的位置的地址保存在内存中,为什么我使用 *w 在那里放置一个字符串。不应该是 *(*w) 吗?由于 *w 是保留内存的地址,那么 *(*w) 就是这块内存的内容。

总结。我不明白的是: 1) 为什么 wpisuj (char **w) 而不是 wpisuj (char *w) 2) 为什么 strcpy(w, bufor) 而不是 strcpy((*w), bufor)

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
# define SIZE 256

void wpisuj(char** pw){
  char bufor[256];
  scanf("%s", bufor);
  int l;
  l=strlen(bufor)+1;
  *pw=(char*)malloc(l*sizeof(char));
  strcpy(*pw, bufor);
}


int main(){
  char* w;
  wpisuj(&w);
  printf("%s", w);  

   return 0;
}

如果我还可以询问有关释放内存的问题。我认为这是正确的星星数量是否正确(如下面的代码所示):

void free_memory(char **w){
   free(*w);
}

但是,如果我在 main() 中释放内存,我会:

int main(){
  w=malloc(sizeof(buffer)+sizeof(char));
/* some code before */
  free(w);
}

【问题讨论】:

  • 两颗星,因为它是一个指向指针的指针......
  • * = 指针。 ** = 指向指针的指针。就是这样
  • 如果在函数中使用不同的变量名会有所帮助。函数的w 是指向main 的w 的指针。也许称它为pw。那么函数中的*pw与main中的w表示同一个变量。
  • 谢谢你,Matt - 是的,在函数中更改变量的名称是个好主意,让我更容易理解。

标签: c pointers memory


【解决方案1】:

为什么我需要一个双指针?

这就是我理解你的问题。答案是:因为像所有实际参数(这是调用者传递的值的副本),传递给函数的指针将在它们实际声明的范围内保存它们的值(其中在这种情况下是被调用函数的作用域),而不更改调用函数中的任何内容。而这不是你想要的,因为你想改变w的值。

如果你这样做:

void MyFunction(int* p) {
    //`p`'s value, like `a`'s value, is NULL
    *p=(char *)malloc(256*sizeof(char));
    //`p`'s value is the starting address of the buffer, but `a` didn't change
    return;
}

int main() {
    char* a;
    a=NULL;
    MyFunction(a);
    return 0;
    //`a`'s value is still NULL, because MyFunction() changed only its own copy of `a`
}

什么都没有发生,因为您只是在MyFunction() 中更改了p 指向的地址。

所以,就像你对整数所做的那样:

void MyFunction(int* p) {
    *p=1;
    return;
}

int main() {
    int a;
    a=0;
    MyFunction(&a);
    printf("%d", a);
    return 0;
}

对指针做同样的事情:

void MyFunction(int** p) {
    *p=(char *)malloc(256*sizeof(char));
    return;
}

int main() {
    char* a;
    a=NULL;
    MyFunction(&a);
    return 0;
}

我不明白为什么在定义函数及其参数时需要两颗星。我正在传递一个指向 char 变量的指针。

为什么不 void wpisuj(char * w)。为什么是 wpisuj(char** w)。

看看你的代码:

wpisuj(&amp;w);

这里的符号取消引用指针w。这意味着整个表达式&amp;w 具有w地址 的值。所以你传递的是一个指向char变量的指针的地址,它是一个指向一个char变量的指针。这是正确的:如果您需要更改整数,则传递整数的地址。如果需要更改指针,则传递指针的地址。因此使用wpisuj(char** w) 甚至是正确的。

还有一些我不明白的地方,如果 *w 是指针并将新创建的位置的地址保存在内存中,为什么我使用 *w 来放置一个字符串。

因为你没有放置一个字符串:如果w(在wpisuj()内)像之前所说的是一个指向char的指针,*w(在wpisuk()内)是一个指向char的指针,这相当于main() 中的*(&amp;w),这是main()w 的值。所以你正在做的是将malloc() 返回的值分配给main() 中的指针w

【讨论】:

    【解决方案2】:

    下面的代码显示了做同样事情的不同方法。主要区别在于wpisuj 函数返回 指向新分配的字符串的指针(main 然后分配给w)。这种技术避免了使用指向指针的指针,因为wpisuj 不需要修改wmain's 副本。

    其他区别

    • 错误检查:检查来自scanfmalloc 的返回值
    • 没有内存泄漏:最后是free( w )
    • 更好的安全性:%255s in scanf 防止用户溢出缓冲区

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    char *wpisuj( void )
    {
        char bufor[256];
    
        if ( scanf( "%255s", bufor ) != 1 )
            return( NULL );
    
        char *w = malloc( strlen(bufor) + 1 );
    
        if ( w != NULL )
            strcpy( w, bufor );
    
        return( w );
    }
    
    int main()
    {
        char *w;
    
        if ( (w = wpisuj()) != NULL )
        {
            printf( "%s\n", w );
            free( w );
        }
    
        return 0;
    }
    

    【讨论】:

      【解决方案3】:

      考虑一下下面的简单程序会很清楚

      #include <stdio.h>
      
      void f( int x )
      {
          x = x + 20;
      }
      
      int main(void) 
      {
          int x = 10;
      
          printf( "Before the call f( x ) x = %d\n", x );
      
          f( x );
      
          printf( "After  the call f( x ) x = %d\n", x );
      
          return 0;
      }
      

      输出将是

      Before the call f( x ) x = 10
      After  the call f( x ) x = 10
      

      如您所见,函数 f 中的 x 没有被修改,因为该函数处理 main 中定义的对象 x 的副本。

      但是,如果您将按照以下方式重写函数

      #include <stdio.h>
      
      void f( int *x )
      {
          *x = *x + 20;
      }
      
      int main(void) 
      {
          int x = 10;
      
          printf( "Before the call f( x ) x = %d\n", x );
      
          f( &x );
      
          printf( "After  the call f( x ) x = %d\n", x );
      
          return 0;
      }
      

      那么在这种情况下,输出将是

      Before the call f( x ) x = 10
      After  the call f( x ) x = 30
      

      因为我们将原始对象 x 的地址传递给函数,而在函数内部,原始对象本身已被更改。

      您的帖子中的指针也是如此。

      如果你要定义一个指针

      char *p;
      

      在 main 中并将其作为参数传递给函数

      void f( char *p );
      

      然后该函数将处理原始对象的副本。副本的任何更改都不会影响原始指针。因此,在第一个示例中,您应该传递一个指向 this 指针的指针,该函数应该声明为

      void f( char **p );
      

      你必须这样称呼它

      f( &p );
      

      【讨论】:

        【解决方案4】:

        好吧,我将解释一下我对您的问题的理解: 每当您想使用函数更改变量时,都需要发送其地址,否则在函数内部您将更改本地副本(函数的本地副本),一旦返回,它将丢失。

        1) 基本上,在您的 ma​​in 中,您创建一个指向 nothing 的指针,然后调用函数 wpisuj() 来生成它指向某事。使用上面的想法,你必须发送你的指针的内存位置,这样函数才能改变它指向的位置。如果您只发送w 而不是&amp;w,您将发送地址的副本到它指向的位置并且无法更改它。

        2) 你的函数strcpy 需要一个特定的输入,它是string 的地址,而不是你指针的地址。因此,您可以使用 *w 来获取您的 w 指向的位置。

        【讨论】:

          【解决方案5】:

          wpisuj 传递char** 的原因是,当在函数中分配内存并分配给*w 时,当您从wpisuj 返回时,调用函数中可以看到更改。

          如果你有:

          void wpisuj(char* w){
            char bufor[256];
            scanf("%s", bufor);
            int l;
            l=strlen(bufor)+1;
            w=(char*)malloc(l*sizeof(char));
            strcpy(w, bufor);
          }
          

          w 的更改只是本地更改。调用函数看不到变化。

          【讨论】:

            猜你喜欢
            • 2021-03-09
            • 1970-01-01
            • 2020-12-22
            • 1970-01-01
            • 1970-01-01
            • 2015-06-03
            • 2015-10-15
            • 1970-01-01
            • 2019-08-17
            相关资源
            最近更新 更多