简体   繁体   中英

why do I get Segmentation fault (core dumped) even when I have access to the memory?

I understand that there are better implementations of this reverse string function, I even have made one better than this, but I just want to know why this isn't working.

I have _strlen(char *) function that returns the length of a string.

Here is my code:

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

void rev_string(char *s)
{    
        int length = _strlen(s);
        char *clone = s;
        char *tmp = malloc(length * sizeof(char));

        tmp += length;

        while (*clone)
        {
                *tmp = *clone;
                tmp--;
                clone++;
        }

        tmp += 1;

        //so if you print this and check it you can see the reversing was successful
        //but I couldnt assign it back to the main string;
        printf("TMP-->%s,s-->%s\n",tmp,s);
        
        //I have debugged the problem to be in the next while loop
        while (*tmp)
        {
                *s = *tmp;
                tmp ++;
                s++;
       }    
}

int main(void)
{
        char *str;
        str = "five";
        rev_string(str);
        printf("done");
        printf("%s\n",str);
        return (0);
}

I am trying to understand pointers in-depth and I don't really know much about them at this point so I really appreciate any answer.

Comment of @user3121023 completely correct.

but even if you do s = tmp that will not work because s it's just a copy. Althoug your code can work if will pass **s

void rev_string(char **s)

int length = _strlen(*s);

Replace whole last loop with *s = tmp

This will work as you expected. But never do this in real programs, it's bad solution.

According to the documentation of string literal :

String literals are not modifiable (and in fact may be placed in read-only memory such as .rodata). If a program attempts to modify the static array formed by a string literal, the behavior is undefined.

Example:

char* p = "Hello";
p[1] = 'M'; // Undefined behavior
char a[] = "Hello";
a[1] = 'M'; // OK: a is not a string literal

So, this

char *str = "five";

needs to be

char str[] = "five";

to be modifiable.


This statement

tmp += length;

makes tmp to point to the memory one element after the allocated array.

And, accessing it first time with

*tmp = *clone;

is out-of-bounds access which is Undefined Behavior .

You can verify this with valgrind .


You need to allocate one extra character to accommodate the null-character so the length would be:

const size_t length = strlen(s) + 1;

and, the allocation would be:

char* tmp = malloc(length * sizeof(*tmp));
//                          ^^^^^^^^^^^^
//                          sizeof to variable idiom

The allocated memory needs to be freed after use to avoid the memory leak.


Here's the working example ( live ):

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

void rev_string(char *s)
{
    const size_t length = strlen(s) + 1;
    char *clone = s;
    char *tmp = malloc(length * sizeof(*tmp));

    char *p = tmp + length - 1;
    *p = '\0';

    p--;

    while (*clone)
    {
        *p = *clone;
        p--;
        clone++;
    }

    ++p;

    printf("TMP: %s, s: %s\n", p, s);
    
    while (*p)
    {
        *s = *p;
        p++;
        s++;
    }

    free(tmp);
}

int main()
{
    char str[] = "five";
    rev_string(str);
    printf("%s\n",str);
    return (0);
}

Output:

TMP: evif, s: five
evif

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM