序言:我不敢相信!当我学习 C 基础知识时(不是双关语),我对这种表达方式感到困惑。这就是为什么我会在“解析代码”部分中详细介绍。
解析代码
第一个问题是解析代码
欢迎来到暮光之城
str = (char *) malloc (sizeof(char) * (num+1));
在使用 C/C++ 时,解析这种表达式是强制性的,所以我们将把它分解成它的组件。我们在这里看到的第一件事是这样的:
variable = (expression) function (expression) ;
我第一次看到它时,我只是“嘿,我不敢相信有一种编程语言可以通过将函数的参数放在函数调用的左侧和右侧来调用函数!”。
解析这行代码?
事实上,这一行应该读成这样:
variable = function_a (function_b (expression)) ;
在哪里:
expression is sizeof(char) * (num+1)
function_b is malloc
function_a is a cast operator
C 类型转换运算符有点不自然
正如在别处已经解释过的,C 风格的演员表操作符更像
(function_a) expression
比起来更自然
function_a(expression)
这解释了整行代码的奇怪之处。
C++ 有更容易理解的东西吗?
请注意,在 C++ 中,您可以使用这两种表示法,但您应该使用 static_cast、const_cast、reinterpret_cast 或 dynamic_cast 而不是上述表示法。使用 C++ 转换,上面的代码行将是:
str = static_cast<char *> ( malloc (sizeof(char) * (num+1)) ) ;
我的 sizeof 比你的大
sizeof 是一个运算符。您可以将其视为处理类型的函数。
您将类型作为参数传递,它将以字节为单位为您提供其大小。
所以,如果你写:
size_t i = sizeof(char) ;
size_t j = sizeof(int) ;
您可能(在 32 位 Linux 上)i 的值为 1,j 的值为 4。
它在 malloc 中的使用就像是说“我想要足够的空间来放置 25 辆 4 米长的汽车”而不是“我想要至少 100 米”。
关于 Malloc 的一些东西
Malloc的参数是一个size_t,也就是一个无符号整数。你给它以字节为单位的大小,如果成功,它会返回分配内存的地址,该地址足够大,可以用作数组。例如:
int * p = (int *) malloc (25 * sizeof(int)) ;
然后 p 指向一个内存,您可以在其中并排放置 25 个整数,就好像在一个索引从零到大小为一的数组中一样。例如:
p[0] = 42 ; // Ok, because it's the 1st item of the array
p[24] = 42 ; // Ok, because it's the 25th item of the array
p[25] = 42 ; // CORRUPTION ERROR, because you are trying to
// use the 26th item of a 25 items array !
注意:你也有指针算术,但这超出了问题的范围。
num + 1?
C 风格的字符串与其他语言的字符串有些不同。
字符串的每个字符都可以是任何值,但不能为零。
因为零(也称为 \0)标志着 c 字符串的结尾。
换一种说法:你永远不知道 c 字符串的大小,但是通过搜索 \0 字符,你可以知道它的结束位置(顺便说一句,这是缓冲区溢出和堆栈损坏的原因之一)。
例如,字符串“Hello”似乎有 5 个字符:
"Hello" seems to be an array containing 'H', 'e', 'l', 'l' and 'o'.
但实际上,它有 6 个字符,最后一个是字符 ZERO,使用转义字符 \0 表示。因此:
"Hello" is an array containing 'H', 'e', 'l', 'l', 'o' and 0.
这说明当您想为“num”个字符的字符串分配足够的空间时,您应该分配“num + 1”个字符。