简单地说。这段代码:
var = foo();
var = bar();
在所有
1 情况下
都等于100%:
foo();
var = bar();
此外,如果foo()
没有副作用,那么它与最后一行的结果是100%等效:
// foo();
var = bar();
这适用于任何功能,包括malloc
。如果我们暂时忘记malloc
所做的事情,而只关注刚刚说过的话,我们可以迅速意识到这段代码的注释中写的是什么:
answer = malloc(inputLength + 1);
// Here,the variable answer contains the return value from the call to malloc
answer = input;
// Here,it contains the value of input. The old value is overwritten,and
// is - unless you saved it in another variable - permanently lost.
malloc
的确很简单。它返回一个指向内存块的指针,如果分配失败,则返回NULL指针。 2 就是这样。与ptr = malloc(size)
之类的调用相比,您所做的工作绝对不过是将地址存储在指针变量ptr
中而已。指针变量的使用方式与int
或float
之类的其他变量相同。 int
存储一个整数。指针存储一个存储器地址。这里没有魔术。
1 它是100%等效的,除了您正在做一些花哨的事情,例如使用外部程序读取变量var
2 malloc(0)
可以返回非空指针,但实际上并没有什么不同,因为取消引用将是未定义的行为,并且分配零字节是相当不错的没有意义的(哈哈,指向)操作。
,
要回答这个问题,让我们先来看一个稍微简单一些的代码片段。
int answer;
answer = 42;
answer = 0;
即使是最粗略的观察者也会注意到,第一次作业
answer = 42;
是没有用的。它将42
的值放入answer
中,仅在下一刻被丢弃并替换为0
。这样那行代码就可以完全扔掉。
让我们通过查看optimised assembly code generated by a C compiler进行验证。如我们所见,行answer = 42;
的确对生成的机器代码没有任何影响。
现在将其与相关代码进行比较
answer = malloc(inputLength + 1);
answer = input;
如果类推推理在这种情况下有效,那么我们必须得出结论,第一个分配是无用的,可以省略。我们将某些东西(malloc
的结果)放置在answer
中,只待一会儿扔掉并换成其他东西。
当然,如果没有进一步的研究,我们不能说它是否适用,但是可以通过再次查看生成的程序集来证实我们的怀疑。 And it is confirmed。编译器甚至不会生成对malloc
和strlen
的任何调用!他们确实没用。
那么直觉在哪里
它为答案分配了适当的内存量,然后将输入复制到答案中
崩溃了吗?
问题出在指针和数组之间的永恒困惑。
人们可能经常看到这样的说法:在C中,数组是指针,或者指针是数组,或者数组和指针是可互换的,或者是其多种变体。这些主张都是虚假和误导的。指针和数组是完全不同的东西。他们经常在一起工作,但这远非相同。让我们在代码示例中分解指针和数组。
-
input
是一个指针变量
-
input
(大概)指向一个字符串,该字符串是char
的数组
-
answer
是另一个指针变量
-
malloc(...)
动态分配char
的新数组,并返回指向所述数组的指针
-
answer = malloc(...)
将该指针复制到answer
,现在answer
指向由malloc
分配的数组
-
answer = input
将另一个指针(我们已经在上面看到)复制到answer
- 现在
answer
和input
指向同一字符串,并且malloc
的结果被忘记并丢弃
所以这解释了为什么您的代码正在执行您期望的操作。而不是拥有字符串“ Hello world!”的两个相同副本。您只有一个字符串和两个不同的指针。这似乎就是医生的命令,但是一旦我们做一些稍微复杂的事情,它就会崩溃。例如,这样的代码
char *lineArray[MAX_LINES];
char buffer[BUF_LEN];
int i = 0;
while (i < MAX_LINES && fgets(buffer,BUF_LEN,stdin)) {
lineArray[i++] = copyStr(buffer);
}
最后将stringArray
的每个元素都指向相同的字符串,而不是指向stdin
的一堆不同的行。
好,所以现在我们确定answer = input
复制了一个指针。但是我们要复制一个数组,我们刚刚为其分配了空间!我们该怎么做?
由于我们的数组大概是NUL终止的字符串,因此我们可以使用设计用于复制NUL终止的字符串的标准库函数。
strcpy(answer,input);
对于其他数组,我们可以使用memcpy
。主要区别在于我们必须传递数组长度。
memcpy(answer,input,inputLength + 1);
在我们的情况下,这两种变体都可以使用,但是首选第一种,因为它重申我们正在处理字符串。为保证完整性,这是固定的copyStr
:
char* copyStr(char* input) {
int inputLength;
char *answer;
inputLength = strlen(input);
answer = malloc(inputLength + 1);
strcpy(answer,input);
return answer;
}
顺便说一句,它的工作原理与非标准但广泛使用的strdup
函数相同(strdup具有更好的签名和有效的错误检查,在此我们省略了)。
本文链接:https://www.f2er.com/3054914.html