在C中使用双指针

nle07wnf  于 2022-12-03  发布在  其他
关注(0)|答案(4)|浏览(134)

我正在做一个任务,我应该使用getline函数从终端读取用户的输入。下面是我的代码:

int main(int ac, char **av)
{
        printf("Write something: \n");
        char **buf = NULL;
        size_t buf_size = 0;

        ssize_t bytes_read = getline(buf, &buf_size, stdin);
        if (bytes_read != -1)
                write(STDOUT_FILENO, buf,  buf_size);
        else
                printf("An error occured\n");
        free(buf);
        return (0);
}

从上面的代码中.我的程序显示了文本:发生了一个错误。做了一些代码重构,这是我得出的结果:

int main(int ac, char **av)
{
        printf("Write something: \n");
        char *buf = NULL;
        size_t buf_size = 0;

        ssize_t bytes_read = getline(&buf, &buf_size, stdin);
        if (bytes_read != -1)
                write(STDOUT_FILENO, buf,  buf_size);
        else
                printf("An error occured\n");
        free(buf);
        return (0);
}

瞧!代码显示了输入的任何内容,正是我想要的。所以我修复了这个问题。但是我想知道的是第一个代码片段有什么问题?这样做是对的吗?:char **name = "John Doe";char **name = NULL;
我在一个在线编译器上做了一些快速测试。代码如下:

int main() {
    // Write C code here
    char **name = "John Doe";
    printf("%p\n", name); //0x55f5f9890004
    printf("%p\n", *name); //0x656f44206e686f4a
    printf("%c\n", *name); //J
    printf("%p", "John Doe"); //0x55f5f9890004

    return 0;
}

我意识到双指针只是被当作一个字符指针。不确定我的发现是否正确。如果你能给予一个更好的解释上面的主要功能,这将是很酷。

mwg9r5ms

mwg9r5ms1#

当你想改变一个函数中的变量时,你需要通过引用传递它。否则,函数将处理一个原始对象的值的副本,作为参数表达式使用,并且改变值的副本不会影响原始对象的值。
在C语言中,通过引用传递意味着通过指向对象的指针间接传递对象。
因此,解除指针的引用,函数将直接访问原始对象,并可以更改它。
在此代码片段中

char *buf = NULL;                                                                                                                                       
    size_t buf_size = 0;                                                                                                                                    
                                                                                                                                                            
    ssize_t bytes_read = getline(&buf, &buf_size, stdin);

在调用函数getline之后,你希望指针buf指向函数中读取的字符串,所以你需要像传递另一个变量buf_size一样通过引用将它传递给函数,该变量的值也在函数中改变,函数的调用者需要知道变量的结果值。
如果你肯写

char **buf = NULL;                                                                                                                                       
    size_t buf_size = 0;                                                                                                                                    
                                                                                                                                                            
    ssize_t bytes_read = getline(buf, &buf_size, stdin);

则其自身内的函数将试图解引用导致未定义行为的空指针buf,因为它认为所谓的“双指针”指向函数需要改变的类型char *的对象。
为了更清楚地说明这一点,请考虑以下演示程序。

#include <stdio.h>

void f( char *s )
{
    s = "World!";
}

int main( void )
{
    char *s = "Hello";

    printf( "Before calling f s = %s\n", s );

    f( s );

    printf( "After  calling f s = %s\n", s );
}

程序输出为

Before calling f s = Hello
After  calling f s = Hello

指针s传递给函数的是值。也就是说,函数处理的是指针值的副本。更改副本不会影响指针s的原始值。
现在考虑下一个程序

#include <stdio.h>

void f( char **s )
{
    *s = "World!";
}

int main( void )
{
    char *s = "Hello";

    printf( "Before calling f s = %s\n", s );

    f( &s );

    printf( "After  calling f s = %s\n", s );
}

程序输出为

Before calling f s = Hello
After  calling f s = World!

也就是说,当指针s通过引用传递给函数时,函数可以通过解引用传递给函数的指向原始指针s的指针来改变原始指针s

char **name = "John Doe";

则编译器应发出声明错误的消息。用作初始化器的字符串文字被隐式转换为指向其char *类型的第一个元素的指针。但初始化的变量具有char **类型,并且这些指针类型之间没有隐式转换。
此外,转换说明符%s需要char *类型的参数,而不是char **类型的参数。
所以你必须写

char *name = "John Doe";

或者,由于您不能更改字符串文字,因此最好将声明编写为

const char *name = "John Doe";
uurity8g

uurity8g2#

char *buf的情况下,getline将转到指针buf的存储器位置并改变该地址。
char **buf = NULL;的情况下,getline将去内存位置“null”,并试图改变该地址,这是毫无意义的。你本质上是对getline撒谎,告诉它你在内存位置“null”为它存储了一个指针。
至于char **name = "John Doe";,它违反了C的赋值规则,任何事情都可能发生,因为代码不是有效的C。包括“似乎一直工作得很好,直到几年后在实际生产代码中发生神秘的崩溃”。

bwitn5fc

bwitn5fc3#

一个双指针必须引用一个有效的指针才能工作(因为该指针将存储对新分配的内存的引用。

int main(int ac, char **av)
{
        printf("Write something: \n");
        char *realBuf = NULL
        char **buf = &realBuf;
        size_t buf_size = 0;

        ssize_t bytes_read = getline(buf, &buf_size, stdin);
        if (bytes_read != -1)
                write(STDOUT_FILENO, *buf,  buf_size);
        else
                printf("An error occured\n");
        free(*buf);
        return (0);
}
2nc8po8w

2nc8po8w4#

在C语言中没有“双指针”,因此不能使用它们。
但是对于任何类型的T,你都可以创建一个“指向T的指针”类型。如果T也是一个指针类型,那就是这种情况。这是一个指向指针的指针。而不是一个“双指针”。如果你把char**看作一个“双指针”,你将永远感到困惑。

相关问题