我有以下程序想要修改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上编译程序。
参考:
答案 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)
,它会打印字符串。