Dynamic Memory Allocation

1. Which of the following statements are true.

1. Every call to malloc may not be successful.

Ans: True.

 

2. Memory allocated by malloc is automatically initialised to all zeros.

Ans: False. Allocated memory is uninitialized.

 

3. If we do not check return value of malloc, our program could crash.

Ans: True. If call to malloc fails, it will return NULL. Dereferencing NULL pointer can cause our program to crash.

 

4. We should not call malloc again until we have called free for already allocated memory.

Ans: False. We can call malloc as many times as necessary. As good programming practice, we should free all memory that we no longer need.

 

5. Dynamically allocated memory can be accessed like an array.

Ans: True.

 

 

2. Implement functions compute_average and read_score in the above example.

#include <stdio.h>
#include <stdlib.h>

/* We need an additional parameter to determine number of elements to process.
 * Same as we needed for array processing */
/* Return type of compute_average should be float or double and not int */
double compute_average(int *, int);
void read_score(int *, int);

int main (int argc, char * argv[]) {
    int *score = NULL, num_students = 0;
    double average = 0;

    printf ("Please enter number of students: ");
    scanf("%d",&num_students);
    if (num_students <= 0) {
        printf ("Invalid input. Terminating\n");
        return 1;
    }

    score = malloc (sizeof(int) * num_students);
    if (NULL == score) {
        printf ("Failed to allocate memory. Terminating\n");
        return 1;
    }

    read_score(score, num_students);
    average = compute_average(score, num_students);
    printf("Average score of the class is %f\n", average);

    free(score);
    return 0;
}

double compute_average(int *score, int num){
    int sum = 0;
    for(int i=0; i<num; i++){
        sum += score[i];
    }
    return ((double)sum)/num;
}

void read_score(int *score, int num) {
    for(int i=0; i<num; i++){
        printf("Enter score of student #%d: ",i+1);
        scanf("%d", &score[i]);
    }
}

 

 

3. Trace control flow of above example for user input “Pragati” and “Priyanka”.

 

01: #include <stdio.h>
02: #include <stdlib.h>

   /* This function returns longest common prefix of strings ptr1 and ptr2 */

03: char * longest_prefix (char *ptr1, char *ptr2) {
04:     char *itr1 = NULL, *itr2 = NULL, *prefix = NULL;
05:     int count = 0;
06:     itr1 = ptr1;
07:     itr2 = ptr2;

08:     while (*itr1 != '\0' && *itr2 != '\0') {
        /*Loop terminates as soon as end of any one string is reached*/
09:         if (*itr1 != *itr2) {
            /* strings do not match beyond this point */
10:             break;
            }
11:         count++; /* char matched, increment count*/
12:         itr1++;  /* point itr1 to next char in ptr1*/
13:         itr2++;  /* point itr2 to next char in ptr2*/
14:     }

    /* count holds number of matched characters in prefix. Allocate 1 extra byte for terminating ‘\0’ */
15:     prefix = malloc (count + 1); 

16:     if (NULL == prefix) {
17:         printf ("Error allocating memory");
18:         return NULL;
19:     }

        /* Prepare result to return */
20:     for (int i=0; i<count; i++){
21:         prefix[i] = ptr1[i];
22:     }
23:     prefix[count] = '\0';

24:     return prefix;
25: }

26: int main (int argc, char * argv[]) {
27:     char str1[32] = { 0 }, str2[32] = { 0 };
28:     char *result = NULL;

29:     printf("Enter string 1, under 31 characters: ");
30:     scanf("%31s", str1);
31:     printf("Enter string 2:, under 31 characters ");
32:     scanf("%31s", str2);

33:     result = longest_prefix (str1, str2);

34:     if (result) {
35:         printf("longest common prefix is \"%s\"\n", result);
36:         free (result);
37:     } else {
38:         printf("Error in finding common prefix\n");
39:         return 1;
40:     }

41:     return 0;
42: }


Ans:

  1. After user input, control reaches line 33. This is call to longest_prefix. Control jumps to line 03. ptr1 is pointing to first char of “Pragati” and ptr2 is pointing to first char of “Priyanka”.
  2. After initializations, control reaches line 08. itr1 is pointing to first char of “Pragati”, itr2 is pointing to first char of “Priyanka”. while loop control condition evaluates to true. Control advances to line 09.
  3. Since both itr1 and itr2 are pointing to ‘P’, condition evaluates to false. Control jumps to end of if, line 11.
  4. Value of count is incremented to 1. Control advances to line 12.
  5. itr1 is incremented. It now points to char ‘r’ in string “Pragati”. Control advances to line 13.
  6. Itr2 is incremented. It now points to char ‘r’ in string “Priyanka”. Control reaches end of while loop iteration and jumps to line 08.
  7. while loop control condition evaluates to true. Control advances to line 09.
  8. Since both itr1 and itr2 are pointing to ‘r’, condition evaluates to false. Control jumps to end of if, line 11.
  9. Value of count is incremented to 2. Control advances to line 12.
  10. itr1 is incremented. It now points to char ‘a’ in string “Pragati”. Control advances to line 13.
  11. Itr2 is incremented. It now points to char ‘i’ in string “Priyanka”. Control reaches end of while loop iteration and jumps to line 08.
  12. while loop control condition evaluates to true. Control advances to line 09.
  13. Since itr1 is pointing to ‘a’ and itr2 is pointing to ‘i’, condition evaluates to true. Control enters if block, line 10.
  14. break causes control to jump out of while block, line 15.
  15. Value of count was 2. We allocate 3 bytes of memory using malloc and assign address to variable prefix. Let us assume the call was successful.
  16. Control advances to line 16. Since malloc was successful control expression evaluates to false. Control jumps to line 20.
  17. Control expression 0<2 evaluates to true. Control enters for loop. Line 21.
  18. ptr1 still points to ‘P’ in “Pragati”. ‘P’ is copied to index 0 of prefix.
  19. Control reaches end of iteration. Tail statement is executed, value of i becomes 1.
  20. Control expression 1<2 evaluates to true. Control enters for loop. Line 21.
  21. ptr1 still points to ‘P’ in “Pragati”. So ptr[1] refers to character ‘r’ in “Pragati”.
  22. ‘r’ is copued to index 1 of prefix.
  23. Control reaches end of iteration. Tail statement is executed, value of i becomes 2.
  24. Control expression 2<2 evaluates to false. Control jumps to outside for loop. Line 23.
  25. ‘\0’ is placed at index 2 of prefix. Now prefix contains string “Pr”.
  26. Control advances to line 24 and prefix is returned. Control jumps to line 33.
  27. Address in prefix is assigned to variable result. Note that since prefix pointed to dynamically allocated memory, we can access the memory even after longest_prefix function has returned.
  28. Control advances to line 34. Since result is not NULL, control expression evaluates to true. Control enters if block, line 35.
  29. Message longest common prefix is Pr is printed to the console.
  30. Control advances to line 36. Dynamically allocated memory whose address we had stored in result is freed.
  31. Control reaches end of if block, skips else block, line 41.
  32. Program terminates.

 

 

4. Which of the following statements are true.

1. When address returned by malloc is assigned to a pointer, that pointer remains in scope until free is called.

Ans: False. The pointer variable, assuming it was a local variable, goes out of scope as soon its block is executed. The memory is still accessible though as long as we copy over the address to an inscope variable, e.g. by returning the address from the function.

 

2. Memory leak is a condition in which system’s memory has been exhausted.

Ans: False. Out of memory is the condition in which system’s memory has been exhausted. Memory leak can lead to system going out of memory but these are two different conditions.

 

3. As a good programming practice, free should be called towards end of the program just before return.

Ans: False. We should free up the memory as soon as our purpose of allocating it is fulfilled.

 

 

5. In case of memory leak which segment of memory can be exhausted?

Ans: Heap. Dynamically allocated memory is allocated from heap. Hence in case of memory leak, heap can get exhausted.

 

 

6. Assuming 4 byte int and 4 byte pointer, what will be printed by below code snippet?

int *ptr = malloc(10*sizeof(int));

printf(“%lu\n”,sizeof(ptr));

 

Ans: 4. This statement prints size if int*.

 

 

7. Which of the following statements are true.

1. Return type of malloc is void *.

Ans: True.

 

2. Pointer of any data type can be cast to a void *.

Ans: True.

 

3. A void * can be cast to pointer of any data type.

Ans: True.