-3

I'm trying to document some code to improve my knowledge of pointers and general ANSI C ability.

 ...
 int static_store = 30;
 const char * pcg = "String Literal";
 int main()
 {
     int auto_store = 40;
     char auto_string[] = "Auto char Array";
     int * pi;
     char * pcl;
     pi = (int *) malloc(sizeof(int));
     *pi = 35;
     pcl = (char *) malloc(strlen("Dynamic String") + 1);
     strcpy(pcl, "Dynamic String");
 ...

From first looks, two pointers are initialised, pi and pcl, of type int and char respectively.

But the lines after are confusing to me and I don't understand what is happening. I can see that malloc is being called to allocate memory the size of int (40). Is it assigning memory to the variables pi and pcl?

Zachi Shtain
  • 826
  • 1
  • 13
  • 31
Masutatsu
  • 434
  • 1
  • 7
  • 19
  • 2
    [Please don't cast the result of `malloc()`](http://stackoverflow.com/a/605858/3233393). – Quentin Aug 14 '15 at 13:37
  • 1
    " the size of int (40)" ?? – Jabberwocky Aug 14 '15 at 13:41
  • 1
    Title is missleading. Might had said "Trying to understand" rather than "Documenting". `pi` initialization and use is not conventional. For some reason they are allocating the space for an int in the memory heap instead of the stack (if they defined pi as a simple int). Then they allocate just the space for an string (the content plus the \0 terminator). – Javier Aug 14 '15 at 13:41
  • So basically you are asking "what is the purpose of the malloc function". Your C book should be able to answer that question. – Lundin Aug 14 '15 at 13:46
  • To set terms right: `malloc` does not assign anything. That is done by the _assignment-operator_ `=`. `malloc` also does not return "memory", but the address of an allocated memory block (on successful allocation). And a pointer is the suitable container for an address. **Think about it**. Niote: Do not cast `void *` as returned by `malloc` & friends. C is **not** C++! Warning: Always check the result of system functions which might fail. `malloc` might return a _null pointer_! – too honest for this site Aug 14 '15 at 13:47

4 Answers4

3

Is it assigning memory to the variables pi and pcl?

Yes malloc is allocating memory to these pointers.

pi is allocated memory equal to sizeof(int)(that may vary) and pcl has be allocated memory equal to length of string plus 1(plus 1 for null character).

From first looks, two pointers are initialised, pi and pcl, of type int and char respectively

They are declared not initialized.

Note- Please don't cast return of malloc

Community
  • 1
  • 1
ameyCU
  • 16,489
  • 2
  • 26
  • 41
2

2 pointers are delcared (pi and pcl). At declaration they are not intialized.
pi is then pointed to a block of heap allocated memory that can hold 1 int (the size of this is platform dependant but it would usually be 4 bytes) allocated with the fucntion maloc. Somewhere this memory will have to be explicitely freed with the funtion free - failing to do so will be a memory leak.
The int value 35 is then stored at that memory location. *pi can be read as "what the pointer pi points to" it is effectively the same as pi[0].
pcl is then pointed to a block of heap allocated memory that is large enough to hold 14 char plus a '\0' char (i.e 15 bytes) using the function malloc (as above at some point this memory must be freed).
The 15 characters "Dynamic String\0" is then put in that memory using the function strcpy.

Ricibob
  • 7,505
  • 5
  • 46
  • 65
1

The line: pi = (int *) malloc(sizeof(int)) Actually allocate memory for one int variable. The line afterwards, puts the value 35 into that variable.

The line: pcl = (char *) malloc(strlen("Dynamic String") + 1) Creates a dynamically allocated char array (which is equivalent to a string). The size of that array is of the length of the string ("Dynamic String") plus one. The next line copies the string: "Dynamic String" into the allocated array. The plus one is needed because each string in c ends with the char '\0' which is a sign for the end of a string.

Zachi Shtain
  • 826
  • 1
  • 13
  • 31
0

The malloc function reserves a block of memory in the heap (the dynamic memory pool), and returns a pointer to the first element of that block of memory. That memory is reserved until you call free, or the program exits.

In the call

pi = (int *) malloc(sizeof(int));

malloc reserves a block of memory large enough to store a single int value, and the pointer to that memory block is assigned to pi. You do not need to cast the result of malloc1, and it's actually considered bad practice2. A better way to write that would be

pi = malloc( sizeof *pi );

The expression *pi has type int, so sizeof *pi is equivalent to sizeof (int)3. The advantage of using sizeof *pi over sizeof (int) (as well as dropping the cast) is that if you ever change the type of pi (from int * to long *, for example), you won't have to change anything in the malloc call; it will always allocate the right amount of memory regardless of the type of pi. It's one less maintenance headache to worry about.

Similarly, the call

pcl = (char *) malloc(strlen("Dynamic String") + 1);

reserves enough memory to hold the contents of "Dynamic String" (the +1 is necessary for the string terminator) and assigns the pointer to that memory to pcl. Again, this would be better written as

pcl = malloc( strlen("Dynamic String") + 1 ); // no cast

sizeof (char) is 1 by definition, so you don't need an explicit sizeof *pcl in the call above; however, if you ever decide to change the type of pcl from char * to wchar_t *, it would be good to have it in place, although you'd still have to change the string literal and change how you compute the length, so it's not maintenance-free.

The general form a malloc call is

T *p = malloc( num_elements * sizeof *p ); // where num_elements > 1

or

T *p;
...
p = malloc( num_elements * sizeof *p );

There is a similar function named calloc that will zero out the allocated memory block:

T *p = calloc( num_elements, sizeof *p );

or

T *p;
...
p = calloc( num_elements, sizeof *p );


1. In C, anyway; C++ does require the cast, since C++ does not allow implicit conversions between void * and other pointer types. But you shouldn't be using malloc in C++ code, anyway.

So why do people still cast the result of malloc in C? It's largely a holdover from pre-ANSI days (more than a quarter of a century ago), when malloc returned char *, which cannot be assigned to a different pointer type without a cast. The 1989 standard introduced the void * type, which is essentially a "generic" pointer that can be assigned to other pointer types without an explicit cast.

2. Under the C89 standard, if the compiler sees a function call without having seen a declaration for that function, it will assume that the function returns int. Thus, if you forget to include stdlib.h or otherwise don't have a declaration for malloc in scope, the compiler will assume it returns an int value and generate the machine code for the call accordingly. However, int and pointer types aren't compatible, and normally the compiler will issue diagnostic if you try to assign one to the other. By using the cast, however, you supress that diagnostic, and you may run into runtime problems later on.

The 1999 standard did away with implicit int typing for functions, so that's not really a problem anymore, but the cast is still unnecessary and leads to maintenance problems.

3. sizeof is an operator, not a function; parentheses are only required if the operand is a type name like int or double or struct blah.
John Bode
  • 119,563
  • 19
  • 122
  • 198