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 free
d.
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;
}