0

In the following case, data is not being set as expected and data_handler as well.

int main() {

char    *data;
char    *data_handler;
int      i = 0;
int      len , req;
char     test[10] = "test";

for(; i<10; i++){

    req = snprintf(NULL, 0 , "[%s] ", test);

    printf("%d --> req \n", req);
    if (data == NULL) {
        data = (char *) malloc ((sizeof(char) * req) + 1);
        data_handler = data;
    } else {
        data_handler = data + len;
        data_handler = (char *) malloc ((sizeof(char) * req) +1);
    }

    len += snprintf(data_handler, sizeof(data) , "[%s] ", test);

    printf("\nData --> %s\n", data);
    printf("\nData Handler --> %s\n", data_handler);
} 

printf ("%s", data);

}

Intention of this program is to append total 10 times test in a string. (Experimenting pointers) but I am getting following output.

7 --> req 

Data --> (��

Data Handler --> [te
7 --> req 

Data --> (��

Data Handler --> [te
7 --> req 

Data --> (��

Data Handler --> [te
7 --> req 

Data --> (��

Data Handler --> [te
7 --> req 

Data --> (��

Data Handler --> [te
7 --> req 

Data --> (��

Data Handler --> [te
7 --> req 

Data --> (��

Data Handler --> [te
7 --> req 

Data --> (��

Data Handler --> [te
7 --> req 

Data --> (��

Data Handler --> [te
7 --> req 

Data --> (��

Data Handler --> [te
(��
Exited: ExitFailure 5
Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97

3 Answers3

1

Local variables are not automatically initialized,

char *data;

leaves data unuinitialized and that means it has no value stored in it, it's a random value that might be considered garbage and is unpredictable, but it's very likely that it's not NULL, so the test is false and you are printing data without first initialiazing it.

Also, the sizeof operator returns the size of the type and not the allocated size. You should keep the allocated size in order to use it later. The sizeof operator gives you the size of an array too but data is not an array it's a pointer.

And finally:

  1. Do not cast the return value of malloc(). Read here for more about it.
  2. Don't use sizeof(char) because it's === 1 by definition.
Community
  • 1
  • 1
Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
  • Thank you very much.. after making changes you suggested ..It is showing better result but not the one I am expecting.. As per my code I am adding new "test" at the end of the prev string..So at the end it should print " test test test test test .." but it is printing only one "test" – Kaushik Koneru May 18 '16 at 01:23
1

In addition to the other issues discussed, your code leaks memory badly. You cannot simply continue to malloc data_handler each iteration. When you do, you overwrite the address of the previously allocated block losing the ability to free the previously allocated memory. Instead, you must realloc the original block of memory, preserving the pointer data pointing to starting address for the block of memory and then update data_handler accordingly. This is a fundamental memory management issue.

Instead, it looks like you were attempting to do the following. I apologize if I misinterpreted your goal, but otherwise your code does not make sense:

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

int main (void) {

    char *data = NULL;
    char *data_handler = NULL;
    int i = 0, len = 0, req = 0;
    char test[10] = "test";

    req = snprintf (NULL, 0, "[%s] ", test);
    printf ("%d --> req\n", req);

    for (; i < 10; i++) {

        if (data == NULL) {
            data = malloc (req + 1);
            data_handler = data;
        }
        else {
            char *tmp = realloc (data, len + req + 1);  /* realloc data */
            if (!tmp) { /* validate */
                fprintf (stderr, "realloc() error: virtual memory exhausted.\n");
                return 1;
            }
            data = tmp;                 /* assign tmp to data  */
            data_handler = data + len;  /* update data_handler */
        }

        len += snprintf (data_handler, sizeof test, "[%s] ", test);

        printf ("-- (len: %d)\nData         --> %s\n", len, data);
        printf ("Data Handler --> %s\n", data_handler);
    }
    putchar ('\n');
    free (data);

    return 0;
}

Example Use/Output

$ ./bin/snprintfnoinit
7 --> req
-- (len: 7)
Data         --> [test]
Data Handler --> [test]
-- (len: 14)
Data         --> [test] [test]
Data Handler --> [test]
-- (len: 21)
Data         --> [test] [test] [test]
Data Handler --> [test]
-- (len: 28)
Data         --> [test] [test] [test] [test]
Data Handler --> [test]
-- (len: 35)
Data         --> [test] [test] [test] [test] [test]
Data Handler --> [test]
-- (len: 42)
Data         --> [test] [test] [test] [test] [test] [test]
Data Handler --> [test]
-- (len: 49)
Data         --> [test] [test] [test] [test] [test] [test] [test]
Data Handler --> [test]
-- (len: 56)
Data         --> [test] [test] [test] [test] [test] [test] [test] [test]
Data Handler --> [test]
-- (len: 63)
Data         --> [test] [test] [test] [test] [test] [test] [test] [test] [test]
Data Handler --> [test]
-- (len: 70)
Data         --> [test] [test] [test] [test] [test] [test] [test] [test] [test] [test]
Data Handler --> [test]

Memory Use/Error Check

In any code your write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.

It is imperative that you use a memory error checking program to insure you haven't written beyond/outside your allocated block of memory, attempted to read or base a jump on an unintitialized value and finally to confirm that you have freed all the memory you have allocated. For Linux valgrind is the normal choice. It is simple to use.

$ valgrind ./bin/snprintfnoinit
==25279== Memcheck, a memory error detector
==25279== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==25279== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==25279== Command: ./bin/snprintfnoinit
==25279==
7 --> req
-- (len: 7)
Data         --> [test]
Data Handler --> [test]
-- (len: 14)
...
==25279==
==25279== HEAP SUMMARY:
==25279==     in use at exit: 0 bytes in 0 blocks
==25279==   total heap usage: 10 allocs, 10 frees, 395 bytes allocated
==25279==
==25279== All heap blocks were freed -- no leaks are possible
==25279==
==25279== For counts of detected and suppressed errors, rerun with: -v
==25279== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)

Always confirm All heap blocks were freed -- no leaks are possible and equally important ERROR SUMMARY: 0 errors from 0 contexts.

Look over the changes to the code and let me know if you have any questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
0

After adding this include to the code to get it to compile:

#include <stdio.h>

The compiler gives hints as to why the code is not working as expected:

Microsoft (R) C/C++ Optimizing Compiler Version 19.00.23506 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

test.c
d:\temp\test.c(16) : warning C4700: uninitialized local variable 'data' used
d:\temp\test.c(24) : warning C4700: uninitialized local variable 'len' used

EDIT:

Below is your code with an include file added so that it compiles and the warnings fixed by initilising the variables as suggested by the compiler:

#include <stdio.h>

int main() {

char    *data=0;
char    *data_handler;
int      i = 0;
int      len=0, req;
char     test[10] = "test";

for(; i<10; i++){

    req = snprintf(NULL, 0 , "[%s] ", test);

    printf("%d --> req \n", req);
    if (data == NULL) {
        data = (char *) malloc ((sizeof(char) * req) + 1);
        data_handler = data;
    } else {
        data_handler = data + len;
        data_handler = (char *) malloc ((sizeof(char) * req) +1);
    }

    len += snprintf(data_handler, sizeof(data) , "[%s] ", test);

    printf("\nData --> %s\n", data);
    printf("\nData Handler --> %s\n", data_handler);
}

printf ("%s", data);

}

Here is the output produced by that code:

7 --> req 

Data --> [te

Data Handler --> [te
7 --> req 

Data --> [te

Data Handler --> [te
7 --> req 

Data --> [te

Data Handler --> [te
7 --> req 

Data --> [te

Data Handler --> [te
7 --> req 

Data --> [te

Data Handler --> [te
7 --> req 

Data --> [te

Data Handler --> [te
7 --> req 

Data --> [te

Data Handler --> [te
7 --> req 

Data --> [te

Data Handler --> [te
7 --> req 

Data --> [te

Data Handler --> [te
7 --> req 

Data --> [te

Data Handler --> [te
[te
jussij
  • 10,370
  • 1
  • 33
  • 49
  • I don't think this is the problem. But casting to `(char *)` certainly hides the error. – Iharob Al Asimi May 18 '16 at 01:18
  • The compiler is pointing out that the `data` variable is undefined as it has not been initialized, as is the `len` variable. Because the `data` variable is undefined it also points out the fact that the if statement 'if (data == NULL) {' at line 16 is not going to work as expected and that is definitely the issue. The other warning is no better as this line of code `len += snprintf` could do anything because `len` is undefined. These warnings are there for a reason. – jussij May 18 '16 at 01:26
  • Yes 100% with you. And warnings are very helpful for new programmers. I am just teaching it to my sister exactly how important warnings can be. – Iharob Al Asimi May 18 '16 at 01:50