2

This question may sound stupid but I'm not really sure about it. I mean, what's the difference between:

char* line = (char*) malloc(MAX_LINE_LEN);

and

char line[MAX_LINE_LEN];

exactly? I know the former is a pointer and the latter is an array, but how can the system tell the difference? How is the memory allocated/stored?

Also, why can you delete the memory occupied by line when it's declared as a pointer, but not when it's an array? I think that an array is stored somewhere else and the system automatically deallocates its memory when it's out of scope, which doesn't happen when you are dealing with a pointer so you must delete it yourself. Am I wrong?

Fernando Aires Castello
  • 1,203
  • 3
  • 17
  • 23
  • 5
    This question has eben answered many times, please Look for it – bash.d Apr 27 '13 at 10:03
  • 2
    I don't it's a dup. That one's more about (un)modifiable strings. – luser droog Apr 27 '13 at 10:23
  • Also, the principal difference between the two lines you listed here is that the second declaration is right, the first one is wrong. –  Apr 27 '13 at 10:35
  • Please do not close this question with what dtech suggested. The other question is different from this question. – nhahtdh Apr 27 '13 at 10:44
  • @nhahtdh Is it worth reopening? I'm happy to cast a vote, even if only to have it closed to a more accurate duplicate. – autistic Apr 27 '13 at 10:57
  • @undefinedbehaviour: I think it is worth reopening for a good duplicate (if there is not, it is even better of a reason to do so). – nhahtdh Apr 27 '13 at 10:59
  • @luserdroog It seems like you'll agree. Care to cast a vote? – autistic Apr 27 '13 at 11:00
  • I found a closer [similar question](http://stackoverflow.com/questions/1782369/similarities-and-differences-between-arrays-and-pointers-through-a-practical-exa). Still not quite a dup. – luser droog Apr 27 '13 at 11:49
  • It is thoroughly covered in the [clc FAQ](http://c-faq.com/aryptr/index.html). – luser droog Apr 27 '13 at 12:02
  • 1
    possible duplicate of [stack pointer difference char pointer and array](http://stackoverflow.com/questions/12760229/stack-pointer-difference-char-pointer-and-array) – user93353 Apr 27 '13 at 12:09
  • @user93353 This question asks more than that question. – autistic Apr 27 '13 at 12:47
  • @undefinedbehaviour - multiple questions should be asked as multiple questions, if at all. – user93353 Apr 27 '13 at 14:16
  • @user93353 I just spotted an incredibly popular question, linked to this one [here](http://stackoverflow.com/questions/79923/what-and-where-are-the-stack-and-heap). It seems that 1653 people think it's not inappropriate to ask multiple questions in a question. – autistic Apr 27 '13 at 15:27

4 Answers4

4
char* line = (char*) malloc(MAX_LINE_LEN);

This is poor style; You don't need to cast malloc in C. Let's break this up into two sections, because it's easier to describe and compare that way:

char *line; declares a pointer to char named line. You can assign it to point to an object (or nothing). The sizeof an object is the size of it's type, so sizeof (line) is sizeof (char *), which varies from system to system. &line is the address of a char *, which has the type char ** (pointer to pointer to char). It's storage duration depends upon where it is declared:

  • If it's declared outside of any function, it has static storage duration, which lasts for the lifetime of the program. Objects with static storage duration are initialised to 0, unless an explicit initialisation exists (e.g. in your case). 0 is a null pointer constant, indicating that this object would point to nothing if it were declared outside of functions without an initialiser.

  • If it's declared inside of a block of code, it has automatic storage duration, which lasts until execution reaches the end of that block of code. Objects with automatic storage duration must be explicitly initialised or assigned to before they're used, because their value otherwise is indeterminate.

Your initialisation assigns a value to it, so it won't start off indeterminate regardless. malloc returns a pointer to an object that has dynamic storage duration, which means the object that the pointer points to persists until it is explicitly freed.

Think of this line like the postcode on a mail envelope; You can write something in there, and that something will indicate a location where you can find objects (and people). The postcode doesn't tell you anything about the size of the objects (or people).


char line[MAX_LINE_LEN];

This declares an array of MAX_LINE_LEN chars.

  • If declared outside of any functions, it has static storage duration and the entire array is zero-filled.

  • If declared inside a function or block of code, it has automatic storage duration and the values in the array are indeterminate; They need to be initialised (e.g. char line[MAX_LINE_SIZE] = { 0 }; will initialise all of them) or assigned to (e.g. line[0] = '\0'; will assign to the first element of the array) before they're used.

The type is char[MAX_LINE_SIZE], so the size will be sizeof (char[MAX_LINE_SIZE]), reflected as you can see by the number of elements specified. The address of &line in this case is a char (*)[MAX_LINE_SIZE] (a pointer to an array of MAX_LINE_SIZE chars).

This one can't be reassigned like the one above, so it differs from our postcode example. When an array is used in places where a compiler expects a pointer, the array will be implicitly converted to a pointer to the first element. For example, let us consider:

strcpy(line, "Hello, world!");

The function prototype char *strcpy(char *restrict s1, const char *restrict s2);, tells us that strcpy accepts two char * (pointer to char) arguments. In the example, one of the arguments is a char[MAX_LINE_LEN], and the other is a char[14]. Both got converted to a char *.

This array-to-pointer conversion explains why char *line; line = "hello"; is valid, while char line[MAX_LINE_LEN]; line = "hello"; isn't. You can't change the pointer that results from the conversion.

I know the former is a pointer and the latter is an array, but how can the system tell the difference?

As previously stated, an array expression is converted to a pointer expression when it's used in places where a pointer is expected. For example, array in array[x] is converted to pointer in pointer[x]. What are you asking? Why would it need to know the difference between an array and a pointer?

I think that an array is stored somewhere else and the system automatically deallocates its memory when it's out of scope,

Yes. I explained the different storage durations earlier.

which doesn't happen when you are dealing with a pointer so you must delete it yourself. Am I wrong?

Yes. You're confusing the concept of pointers with the concept of storage duration. int *p = malloc(sizeof *p); p is initialised to point to an int that has dynamic storage duration. That int won't be destroyed until free(p); is called. Both of the variables below, however, have automatic storage duration because they're declared within main, without any qualifiers such as static. p points to i; p is a pointer. Don't free p, because it doesn't point to an object that has dynamic storage duration. free is only defined to destroy objects that have dynamic storage duration.

int main(void) {
    int i = 42;
    int *p = &i;
}
autistic
  • 1
  • 3
  • 35
  • 80
2

Probably the best resource for understanding this is the comp.lang.c FAQ.

Pragmatically, the difference is in the effect of the sizeof operator. sizeof(pointer) gives you the size of a pointer, whereas sizeof(array) gives you ... you guessed it.

When passed as a function argument, an array name decays into a pointer to the first element (losing the sizeof information). In a normal expression, it behaves as if it decayed to a pointer, because the array syntax is defined in terms of the equivalent pointer operations. (In fact early C compilers declared pointers with identifier[].)

A[X]

is, by definition, exactly equivalent to

*(A + X)

with the caveat that in A[X] exactly one of A or X (either one) must be a pointer or array.

Community
  • 1
  • 1
luser droog
  • 18,988
  • 3
  • 53
  • 105
1
char* line;

Allocates pointer on a stack. It will be automatically freed when the program counter will go out of the scope of this declaration.

line = (char*) malloc(MAX_LINE_LEN);

Dynamically allocates MAX_LINE_LEN bytes on the heap. To be precise, you should use malloc in that way:

line = malloc(MAX_LINE_LEN * sizeof(char));

Later you should call free(line) to release this heap memory.

sizeof(line) will return number of bytes taken by the pointer (usually 4 or 8 bytes).


char line[MAX_LINE_LEN];

Allocates MAX_LINE_LEN chars on the stack. It will be automatically freed when the program counter will go out of the scope of this declaration.

sizoef(line) will return MAX_LINE_LEN * sizeof(char) bytes.

Adam Stelmaszczyk
  • 19,665
  • 4
  • 70
  • 110
1

Answer is right there, heap and stack issue.

array, pointer, local variables are stack objects, and heap object is using malloc/free method.

Just take a look at What and where are the stack and heap? for details.

Community
  • 1
  • 1
Daniel
  • 401
  • 3
  • 10
  • 1
    ... and a nonsense one at that. You can't state definitively that objects declared with static storage duration go on either the stack or the heap. They might go in a queue, or become registers. – autistic Apr 27 '13 at 13:03
  • Ok, I'm NOT sure if it's right to use the concept from C++ (the term object) – Daniel Apr 27 '13 at 13:07
  • @Daniel Have you read [the C standard](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf), lately? A mediocre task for you: Count how many times "object" appears in that text. – autistic Apr 27 '13 at 13:08
  • @undefined behaviour OK, I got it. I haven't read the latest standard yet! :) It seems there are many places using object terms. – Daniel Apr 27 '13 at 13:10
  • @Daniel Don't confuse types with storage durations. It's possible to allocate arrays using `malloc`: `int (*ptr_to_array)[20] = malloc(sizeof *ptr_to_array);` ptr_to_array now points to an array that has dynamic storage duration. `NULL` is a pointer that certainly doesn't fall into the "stack objects" category. – autistic Apr 27 '13 at 13:21
  • @undefined behaviour Firstly, I have checked C89, C99(C89-May 13, 1988: http://flash-gordon.me.uk/ansi.c.txt C99-2011: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf C99-2007: http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf). Yes, you are right, it's OK to use object concept. Secondly, int (*ptr_to_array)[20], IMO, ptr_to_array is a pointer, which points to an array of 20 integer. – Daniel Apr 27 '13 at 13:29
  • @Daniel Yes... and the array of 20 `int` it points to resides where: *the stack*, or *the heap*? – autistic Apr 27 '13 at 13:31
  • @undefined behaviour if we use malloc, then it's heap. – Daniel Apr 27 '13 at 13:34
  • @Daniel That's a little more consistent. Good. Is `NULL` an object? – autistic Apr 27 '13 at 13:37
  • @undefined behaviour, Well, from my understanding, NULL is an instance of a pointer. And a variable in the program might be in the heap, stack or even registers. As for a block of memory, compiler will assigned to stack(static), and if the programmer want to use dynamic allocation, we can use malloc/free methods. – Daniel Apr 27 '13 at 14:02