1

I have below code where I have commented when I get segmentation fault and when not.

Originally I got segmentation fault and then I could figure out that probably I cannot initialize my char pointer locations like "abcd". But I am not able to understand - WHY?

I thought testString = "abcd"; will put a at first memory address, b at second and so on ...

Segmentation fault occurs when trying to free memory, based on how I initialize memory location.

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

int main(void)
{
    char* testString = malloc(sizeof(char) * 5);

    printf("Size of char is: %d\n", sizeof(char));
    printf("Size of int is: %d\n", sizeof(int));

    for(int i = 0; i < 5; i++)
    {
        printf("Pointer addresses are: %p\n", testString + i);
    }

    char* tempPtr = testString + 2;
    printf("My temp pointer address = %p\n", tempPtr);

    // This gives me segmentation fault ....
    testString = "abcd";

    // This will not give me segmentation fault ....    
    //int count = 65;
    //for(int i = 0; i < 5; i++)
    //{
    //    testString[i] = count + i;
    //}

    printf("Printing character...\n");

    for(int i = 0; i < 5; i++)
    {
        printf("Characters are: %c\n", testString[i]);
    }

    printf("Freeing memory...\n");
    free(testString);

    //printf("Access after freeing >>%c<<\n", tempPtr[0]);
    //free(testString);
}


Based on @M.M. and @Jonathan's comment I understood that with testString = "abcd"; my testString will point to a memory location where string "abcd" was created and since I didn't malloc'ed it I cannot free it. Also, since my original pointer to heap memory (which I got using malloc) is gone, so it is waste of memory or memory lead.

So, does it means that when I use printf statement like printf("Printing character...\n");, this is also a memory leak? Then how do I avoid it? Looping and inserting into char* is certainly a bad idea.

hagrawal7777
  • 14,103
  • 5
  • 40
  • 70
  • 4
    `testString = "abcd"` means that the pointer `testString` will now point to the memory location containing `"abcd"`. Then you try to `free` that location, causing segmentation fault. – M.M Jan 30 '16 at 22:56
  • 3
    Note that `testString = "abcd";` throws away the pointer to the allocated memory (a memory leak). You need `strcpy()` instead, perhaps. And since the string literal (pointer value) was not returned by `malloc()` (or `calloc()` or `realloc()`), you can't free it. – Jonathan Leffler Jan 30 '16 at 22:58
  • @l3x I didn't want to use some build-in functions and wanted to achieve most basic ways. Thanks for comment though. – hagrawal7777 Jan 30 '16 at 23:07
  • 1
    The memory leak occurs because `testString` contains the only pointer to the allocated memory. When you assign `testString = "abcd"`, you assign a new, different pointer value to `testString`. You can no longer free the pointer that was returned by `malloc()` because you no longer have a record of what it was. The string `"abcd"` exists in your program's memory space somewhere; it isn't a memory leak. It's the pointer overwrite that causes the leak. The `printf("…")` operation does not leak memory. – Jonathan Leffler Jan 30 '16 at 23:15
  • @JonathanLeffler No problem buddy, thanks for your fresh comment. I got it now. So, if I am correct then string "abcd" will be created in stack segment of memory? I don't think it would be created in data segment, and I am not sure about heap segment. – hagrawal7777 Jan 30 '16 at 23:17
  • 1
    The string `"abcd"` will exist somewhere in memory. It is quite likely to be in the text segment since string literals are read-only, but the standard doesn't mandate anything about segments. It won't be in the heap area managed by `malloc()`; it probably won't be on the stack, either. It will most likely either be in the data segment or in the text segment — these days, in the text segment, though historically, it would have been in the data segment. – Jonathan Leffler Jan 30 '16 at 23:20
  • @JonathanLeffler As per my `C` installation, it got created in text segment. I verified using `size` command. – hagrawal7777 Jan 30 '16 at 23:26
  • Possible duplicate of [What is the difference between char s\[\] and char \*s in C?](http://stackoverflow.com/questions/1704407/what-is-the-difference-between-char-s-and-char-s-in-c) – David Hoelzer Jan 31 '16 at 00:21
  • these two lines result in the compiler outputting two warning messages. `printf("Size of char is: %d\n", sizeof(char)); printf("Size of int is: %d\n", sizeof(int));` because the format specifier is expecting an integer parameter and the the returned type from `sizeof()` is `size_t` Suggest changing to: `printf("Size of char is: %lu\n", sizeof(char)); printf("Size of int is: %lu\n", sizeof(int));` – user3629249 Jan 31 '16 at 02:42
  • 1) the expression: `sizeof(char)` is defined in the standard as 1. multiplying by 1 has absolutely no effect on the parameter passed to `malloc()` and just clutters the code. Suggest removing the expression: `sizeof(char)`. 2) when calling any of the memory allocation function, like `malloc()`, always check (!=NULL) the returned value to assure the operation was successful. – user3629249 Jan 31 '16 at 02:45
  • regarding this expression. `printf("Pointer addresses are: %p\n", testString + i);`. there is only one pointer: `testString` and the addresses of the bytes within the allocated memory are going to be consecutive, so are of little to no worth. – user3629249 Jan 31 '16 at 02:48

3 Answers3

1

this line:

testString = "abcd";

is overlaying the pointer given by the call to malloc() with the address of the string literal: "abcd" this results in a memory leak because the original pointer to the allocated memory is lost.

In C, when copying a string, it 'should' be handled by the functions: strcpy() and strncpy() which will not corrupt the pointer contained in testString.

strcpy( testString, "abcd" );
strncpy( testString, "abcd", strlen( "abcd" ) );

Naturally, once the pointer to the allocated memory has been overlayed/destroyed by the assignment statement: testString = "abcd";, the new value placed into testString must not be passed to free()

the seg fault would be happening at the call to free(), not at the incorrect assignment of a new pointer to testString.

user3629249
  • 16,402
  • 1
  • 16
  • 17
  • Thanks for your answer, however it doesn't comprehensively answers my questions. – hagrawal7777 Jan 31 '16 at 14:22
  • @hagrawal, there is only one line in your posted code that causes a memory leak: `testString = "abcd";` a call to `printf()` should never cause a memory leak. – user3629249 Jan 31 '16 at 15:06
1

Using printf is not a memory leak. Memory leaks occur when a pointer is allocated via malloc [or, herein, strdup] and there is no corresponding free call for it.

Also, trying to free a pointer that has not been allocated is another type of error. It [probably] won't segfault, but free will complain.

Here's a simplified version of your program that illustrates some of the ways you can do this:

#include <stdio.h>
#include <string.h>
#include <malloc.h>

int opt_segv;

char *temp = "abcd";

void
dostr(char *str,int modflg)
{

    printf("\n");
    printf("dostr: %s\n",str);
    if (modflg)
        str[modflg] = 'm';
    printf("dostr: %s\n",str);
}

void
test1(void)
{
    int len;
    char *testString;

    len = strlen(temp);
    testString = malloc(len + 1);
    strcpy(testString,temp);

    dostr(testString,1);

    free(testString);
}

void
test2(void)
{
    char *testString;

    testString = strdup(temp);

    dostr(testString,2);

    free(testString);
}

void
test3(void)
{
    char *testString;

    // passing a pointer to a string _constant_ -- do _not_ modify
    testString = temp;

    dostr(testString,opt_segv ? 3 : 0);
}

int
main(int argc,char **argv)
{
    char *cp;

    --argc;
    ++argv;

    for (;  argc > 0;  --argc, ++argv) {
        cp = *argv;
        if (*cp != '-')
            break;

        switch (cp[1]) {
        case 's':  // generate segfault
            opt_segv = 1;
            break;
        }
    }

    test1();
    test2();
    test3();

    return 0;
}

You can run the program with -s to simulate the string constant modification that caused your segfault.

Craig Estey
  • 30,627
  • 4
  • 24
  • 48
  • Thanks for your answer, however it doesn't comprehensively answers my questions. If you had described using comments or some write-up on what you wanted to show from the code example then it would have been better. – hagrawal7777 Jan 31 '16 at 14:23
1

This question has content relevant to answer of my question but doesn't have detailed answer. @Jonathan's comments answers all my questions but he hasn't put forward a detailed answer so I am writing my answer so that folks who will visit further can have detailed explanation:

I created a pointer and allocated some space on "heap segment" of the memory, now my pointer was pointing to that memory location on heap.
Code relevant for all this is - char* testString = malloc(sizeof(char) * 5);.

Now, when I dis this - testString = "abcd"; then string "abcd" is created in "text/code segment" (or in some implementation data segment) of the memory and memory address is returned and assigned to my pointer testString.
What happens is that my original pointer which was pointing a memory location on heap is lost and the pointer started pointing to a memory location on text/code segment of the memory.

Implication of all this:

  • It has resulted in memory leak because my original pointer which was pointing to the heap memory is lost, so now I have no way to free that heap memory and hence memory leak.
  • When I will try to free that memory using free(testString); then I will get segmentation fault (this is exactly what has happened to me) because free() can only be used to free the memory which is allocated using either malloc, calloc or realloc. Now, since the pointer testString is pointing to a memory location on text/code segment and I had not allocated that memory using some C memory allocation method, so I cannot free it using free() and if I do so then I get segmentation fault.
  • When I do testString = "abcd" (when testString is a pointer) then I cannot access the memory location pointed by testString because the memory allocated is read-only in text/code segment of the memory. So, testString[0] = 'x' will also result in segmentation fault.

What happens when I do printf("hello, world")?:
This will create "hello, world" string as read-only in text/code segment of memory. I verified that it does create in text/code segment in C99 implementation using size command.

Community
  • 1
  • 1
hagrawal7777
  • 14,103
  • 5
  • 40
  • 70