简体   繁体   English

当写一个返回指针的 function 时,为什么要分配 memory 给我要返回的指针?

[英]When writing a function that returns pointer, why should I allocate memory to the pointer I'm going to return?

I'm a bit weak when it comes to memory allocation and pointers.当谈到 memory 分配和指针时,我有点弱。 So, I want to understand why do I have to allocate memory to pointers in functions as follow:所以,我想了解为什么我必须将 memory 分配给函数中的指针,如下所示:

char *cstring(char c, int n)
{
int i = 0;
char * res;
res = malloc ((n+1)*sizeof(char));
while (i<n)
{
    res[i]=c;
    i++;
}
res[i] ='\0';
return res;
}

and why is the following not valid?为什么以下无效?

char *cstring(char c, int n)
{
int i = 0;
char * res;
while (i<n)
{
    res[i]=c;
    i++;
}
res[i] ='\0';
return res;
}

I understand that I should allocate memory (generally) to pointers so that they have defined memory.我知道我应该(通常)将 memory 分配给指针,以便它们定义 memory。 However, I want to mainly understand how is it related to the concept of stack and heap memories!但是,我想主要了解它与堆栈和堆内存的概念有什么关系! Thanks in advance!提前致谢!

Pointers need to point to a valid memory location before they can be dereferenced.指针需要指向有效的 memory 位置,然后才能取消引用。

In your first example, res is made to point at a block of allocated memory which can subsequently be written to and read from.在您的第一个示例中, res指向分配的 memory 块,随后可以对其进行写入和读取。

In your second example, res remains uninitialized when you attempt to dereference it.在您的第二个示例中,当您尝试取消引用res时,它保持未初始化 This causes undefined behavior .这会导致未定义的行为 The most likely outcome in this case is that whatever garbage value it happens to contain will not be a valid memory address, so when you attempt to dereference that invalid address your program will crash.在这种情况下,最可能的结果是,它包含的任何垃圾值都不是有效的 memory 地址,因此当您尝试取消引用该无效地址时,您的程序将崩溃。

The second version of your code declares a pointer, but does not initialize it to point to a valid memory address.您的代码的第二个版本声明了一个指针,但没有将其初始化为指向一个有效的 memory 地址。

Then, the code dereferences that pointer -- during the loop.然后,代码在循环期间取消引用该指针。 So, your code would access uninitialized memory in this case.因此,在这种情况下,您的代码将访问未初始化的 memory。 Remember, array indexing is just syntactic sugar for dereferencing -- so your code accesses memory its not supposed to.请记住,数组索引只是解除引用的语法糖——因此您的代码访问 memory 是不应该的。


The first version of your code initializes the pointer to actually point to something, and hence when you dereference it during the loop, it works.您的代码的第一个版本将指针初始化为实际指向某物,因此当您在循环期间取消引用它时,它可以工作。

Of course, in either case, you return the pointer from the function -- its just that in the first version it points to something valid, whereas in the second version it points anywhere .当然,无论哪种情况,您都从 function 返回指针——它只是在第一个版本中指向有效的东西,而在第二个版本中它指向任何地方


The moral here is to always initialize your variables.这里的道德是始终初始化您的变量。 Not doing so could result in undefined behavior in your code (even if it appears to work sometimes).不这样做可能会导致代码中出现未定义的行为(即使它有时似乎可以工作)。 The general advice here is to always compile your code using at least some compilation flags.这里的一般建议是始终使用至少一些编译标志来编译您的代码。 For example in gcc / clang , consider -Wall -Werror -Wextra .例如在gcc / clang中,考虑-Wall -Werror -Wextra Such options often pick up on simple cases of not initializing variables.此类选项通常适用于未初始化变量的简单情况。

Also, valgrind is a brilliant tool for memory profiling.此外, valgrind是 memory 分析的出色工具。 It can easily detect uses of uninitialized memory at runtime, and also memory leaks.它可以在运行时轻松检测未初始化的 memory 的使用,以及 memory 泄漏。

If you declare a variable like that,如果你声明一个这样的变量,

int A = 5;

then that means the variable will be on the stack .那么这意味着变量将在堆栈上。 When functions are called, their local variables are pushed to the stack.当函数被调用时,它们的局部变量被压入堆栈。 The main function is also an example of that.主要的 function 也是一个例子。 So you don't have to allocate memory manually, your compiler will do this for you in the background before it calls your main function.因此,您不必手动分配 memory,您的编译器将在后台为您执行此操作,然后再调用您的主 function。 And that also means if you examine the stack during the execution of the function you can see the value 5.这也意味着如果您在执行 function 期间检查堆栈,您可以看到值 5。

With this,有了这个,

int  A = 5;
int *PtrToA = &A;

The pointer will be on the stack again.指针将再次在堆栈上。 But this time, the value on the stack just shows the memory address of the actual integer value we want.但是这一次,堆栈上的值只是显示了我们想要的实际 integer 值的 memory 地址。 It points to the address of the memory block that holds the value 5. Since A is held in the stack here, pointer will show a memory address on the stack.它指向保存值 5 的 memory 块的地址。由于此处 A 保存在堆栈中,因此指针将显示堆栈上的 memory 地址。 Like the case in your question you can allocate memory dynamically.就像您问题中的情况一样,您可以动态分配 memory 。 But you have to initialize it before you read it.但是您必须在阅读之前对其进行初始化。 Because when you request to allocate the memory, your operating system searches for a valid memory field in your programs heap and reserves that for you.因为当您请求分配 memory 时,您的操作系统会在程序堆中搜索有效的 memory 字段并为您保留该字段。 Than it gives you back its adddress and gives you the read write permissions so you can use it.比它还给你它的地址并给你读写权限,所以你可以使用它。 But the values in it won't contain what you want.但是其中的值不会包含您想要的。 When compiler allocates on stack, the initial values will be unset again.当编译器在堆栈上分配时,初始值将再次取消设置。 If you do this,如果你这样做,

char *res;
res[1] = 3;

variable res will be on the stack and it will contain some random value.变量 res 将在堆栈上,它将包含一些随机值。 So accessing it is just like that,所以访问它就是这样,

(rand())[1] = 3;

You can get an access violation error because you may not have permission to write to that memory location.您可能会收到访问冲突错误,因为您可能无权写入该 memory 位置。

An important note;重要说明; after your function call returns, values of local variables on the stack are no more valid.在您的 function 调用返回后,堆栈上的局部变量值不再有效。 So be careful with that.所以要小心。 Do not dereference them after the function call ends.在 function 调用结束后不要取消引用它们。

In conclusion;综上所述; if you want to use a pointer, be sure it points to a valid memory location.如果要使用指针,请确保它指向有效的 memory 位置。 You can allocate it yourself or make it point another memory address.你可以自己分配或者让它指向另一个memory地址。

Simple: because you do not have any allocated memory for the data you wite.很简单:因为您没有为您写入的数据分配任何 memory。 In your example you define pointer, you do not initialize it so it will reference random (or rather not possible to predict) place in the memory, then you try to write to this random memory location.在您的示例中,您定义了指针,您没有对其进行初始化,因此它将引用 memory 中的随机(或者更确切地说不可能预测)位置,然后您尝试写入此随机 memory 位置。

You have 2 Undefined Behaviours here in 5 lines example.您在 5 行示例中有 2 个未定义的行为。 Your pointer is not initialized, and you did not allocate any valid memory this pointer to reference.你的指针没有初始化,并且你没有分配任何有效的 memory 这个指针来引用。

EDIT:编辑:

VALID有效的

char *cstring(char c, int n)
{
    char * res;
    res = malloc ((n+1)*sizeof(char));
char *cstring(char c, int n)
{
    char * res;
    static char buff[somesize];
    res = buff;
char buff[somesize];
char *cstring(char c, int n)
{
    char * res;
    res = buff;

INVALID无效的

char *cstring(char c, int n)
{
    char * res;
    char buff[somesize];
    res = buff;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM