为什么不能传递指针而不是指向函数的指针?

时间:2018-09-26 00:57:47

标签: c

我有以下程序想要修改s,以便我们可以在最后打印出"Hello World!"

#include <stdio.h>

// modify this function
void function(char** c)
{
    *c = "Hello World!";
}

int main()
{
    char* s;
//    function(&s); 
    function(s);
    puts(s);
    return 0;
}

通常,我们只会做function(&s)。但是,我的问题是为什么我们不能仅使用function(s)?当然,这样做会在编译期间发出警告,但是由于s包含0xab这样的内存地址。如果我们将0xab上的内容从0x00修改为"hello world!",则s持有的地址将保持不变,我们仍然会看到"Hello World!"消息。 / p>

我想知道为什么function(s)在这种情况下不起作用?我在Mac上编译程序。

参考:

2 个答案:

答案 0 :(得分:0)

由于s未初始化,因此其内容是未知的(根据C标准,它的使用无效)。假设它确实包含一些值,并且C实现确实将值function传递给了c。然后function尝试将"Hello World"的地址写到c指向的位置。但是那个地方在哪里?

我们认为s包含一些价值。但这很有可能是未映射到您的地址空间中的地址。您的小程序可能甚至不使用32位地址空间中的大部分,因此操作系统不会将该空间中的大多数映射到实际内存。因此,如果您选择一个随机地址并尝试在其中写入地址,则可能是无效地址,并且您的进程将崩溃。

另一种可能的可能性是s恰好包含零,因为这是在程序的早期,并且没有任何其他东西写入编译器放置s的地方,因此它只包含零操作系统使用来初始化您的内存。在许多系统中,仅出于此目的,故意将零地址保留在地址空间中而不进行映射,这样未初始化指针的使用将崩溃。

更重要的是,一个好的编译器会看到s被使用而没有初始化,并会警告您。如果您仍然强迫它生成代码,则由于其通常的转换,优化器可能会用其他东西完全替换掉这个破损的代码。

如果您不走运,那么未初始化的s将包含一个恰好是您地址空间中有效地址的值,然后function会将"Hello World!"的地址写入它。现在,您正在将数据写到流程中某个地方,而这可能是出于其他目的所必需的,因此它可能以多种方式破坏程序。请注意,这puts不会产生您似乎认为会得到的结果,它会写“ Hello World!”。如果function确实将"Hello World!"的地址写入*c,则该地址将在内存中s恰好指向的位置。然后,您将有地址的地方的地址传递给puts。但是,puts期望有字符的地方的地址。它将读取"Hello World!"地址的字节并进行打印,直到达到零字节为止。大多数情况下,结果是无法打印或至少出现异常字符。

答案 1 :(得分:0)

s未初始化,因此它包含一些垃圾地址(可能是无效的地址)。

当您执行*s = "Hello World!";时,您正在将"Hello World!"(这是一个指针值)写入某个垃圾地址(可能是无效的地址)。

假设它不会崩溃-然后puts将从相同的垃圾地址读取字节(即它将读取字符串的地址,而不是字符串的地址)并在屏幕上显示它们。 / p>

运行错误代码后,内存可能包含以下值,例如:

Address      Value (4 bytes at a time)
...
0x12345678   0x65401234      <- some important thing you just overwrote that is liable to make your program crash,
                                now it holds the address of the string literal
...
0x4000000C   0x12345678      <- variable 's' in main
0x40000010   0x12345678      <- variable 's' in function, copy of variable 's' in main
...
0x65401234   'H', 'e', 'l', 'l'  <- where the compiler decided to put the string literal
0x65401238   'o', ' ', 'W', 'o'
0x6540123C   'r', 'l', 'd', '!'
0x65401240   0

当您呼叫puts(s);时,您将呼叫puts(0x12345678);并且它将打印字节0x65401234(但不会打印“ 0x65401234”,而是会尝试打印字母对应那些)

如果做对了,最终会得到:

Address      Value (4 bytes at a time)
...
0x4000000C   0x65401234      <- variable 's' in main
0x40000010   0x4000000C      <- variable 's' in function, has address of variable 's' in main
...
0x65401234   'H', 'e', 'l', 'l'  <- where the compiler decided to put the string literal
0x65401238   'o', ' ', 'W', 'o'
0x6540123C   'r', 'l', 'd', '!'
0x65401240   0

然后puts(s)puts(0x65401234),它会打印字符串。