C 为什么在将指向字符串的指针传递给函数时使用双星

C 为什么在将指向字符串的指针传递给函数时使用双星,c,pointers,memory,C,Pointers,Memory,在花了很长时间使这段代码正常工作之后,有人能解释一下,当我将指向字符串的指针作为函数的参数传递给函数时,为什么需要两颗星吗? 根据定义,指针将地址保存到某个变量所在的内存中。所以它是一个有自己地址的变量,在这个地址下是另一个变量的地址。可以因此,如果我传递一个指向函数的指针,我会使用符号AND,因为我必须传递指向函数的指针地址。好的 但是接下来会发生什么呢。该函数接收该指针在内存中的位置信息。可以这是我的理解。我不明白的是,为什么我在定义函数及其参数时需要两颗星。我正在传递一个指向char变量的

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

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

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

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

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
的更改只是局部更改。调用函数没有看到更改。

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

1)基本上,在main中,创建一个不指向任何内容的指针,然后调用函数
wpisuj()
,使其指向某个内容。使用上述方法,必须发送指针的内存位置,以便函数可以更改其指向的位置。如果您只发送
w
而不是
&w
,您将发送地址副本到它所指向的位置,并且无法更改它


2) 函数
strcpy
需要一个特定的输入,它是
字符串的地址,而不是指针的地址。因此,您使用<代码> *W>代码>以获得您的<代码> W/COD>指向的位置。

< P>,将清楚地考虑下面的简单程序

#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;
}
正如您所看到的,函数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;
}
因为我们将原始对象x的地址传递给了函数,而在函数内部,原始对象本身也发生了变化

这同样适用于帖子中的指针

如果要定义指针

char *p;
并将其作为参数传递给函数

void f( char *p );
然后该函数将处理原始对象的副本。副本的任何更改都不会影响原始指针。因此,正如在第一个示例中一样,您应该向这个指针传递一个指针,该指针是函数应该声明为

void f( char **p );
你必须这样称呼它

f( &p );

下面的代码显示了执行相同操作的不同方法。主要区别在于
wpisuj
函数返回指向新分配字符串的指针(该字符串
main
然后分配给
w
)。此技术避免使用指针指向指针,因为
wpisuj
不需要修改
main的
w
副本

其他差异

  • 错误检查:检查来自
    scanf
    malloc
    的返回值
  • 无内存泄漏:
    free(w)
    结尾
  • 更好的安全性:
    scanf
    中的
    %255s
    可防止用户溢出缓冲区

#包括
#包括
#包括
char*wpisuj(无效)
{
char-bufor[256];
如果(扫描频率(“%255s”,bufor)!=1)
返回(空);
char*w=malloc(strlen(bufor)+1);
如果(w!=NULL)
strcpy(w,bufor);
返回(w);
}
int main()
{
char*w;
如果((w=wpisuj())!=NULL)
{
printf(“%s\n”,w);
免费(w);
}
返回0;
}

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

这就是我理解你的问题所在。答案是:因为与所有实际参数(它们是调用方传递的值的副本)一样,传递到函数的指针将在实际声明它们的值的范围内保存它们的值(在本例中是被调用函数的范围),而不会更改调用方函数中的任何内容。这不是您想要的,因为您想要更改
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变量的指针

为什么不作废wpisuj(char*w)。为什么是wpisuj(字符**w)

看看你的代码:

wpisuj&w

此处的符号表示取消指针
w
的引用。这意味着整个表达式
&w
的地址值为f( &p );
#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;
}
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`
}
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;
}