2

So I'm trying to reverse a string, but I get a memory fault. Memory for s and s1 is initialized enough to accomodate the '/0' character as well.

Interestingly if I remove *s=*s1 and print s1 instead the program works. But I haven't even set the "\0" character at the end of s1 so how does it even know where to stop printing?

And in the case below what exactly is the issue?

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

void main(void)
{
    char *s = "abcdefghijklmnop", *s1=malloc(17);
    int i;  
    for(i=0;i<strlen(s);i++)
    {
        *(s1+i) = *(s+strlen(s)-1-i);
    }
    *s=*s1;
    printf("%s",s);
}
Stormlight
  • 161
  • 3
  • 10

2 Answers2

3

The char *s = "abcdefghijklmnop" is a string literal which is often in read-only memory. An error will be generated if you attempt to modify a string literal.

You attempt to replace the first character in s with the first character in s1 when you do *s=*s+1.

If s wasn't a string literal, you should've done s=s1 instead of *s=*s1 to make s its reverse.

More about this:

https://softwareengineering.stackexchange.com/questions/294748/why-are-c-string-literals-read-only
String literals: Where do they go?
where in memory are string literals ? stack / heap?

The correct string is printed with printf("%s", s1); even if no \0 was stored because the memory next to the last character just happened to be 0 which is equivalent to \0. This needn't always be so and cannot be relied upon as malloc() doesn't initialise the memory that it allocates.

But calloc() will initialise the memory it allocates to 0.

See more here.

J...S
  • 5,079
  • 1
  • 20
  • 35
  • Ok, so actually *s = *s1 only replaces the first character? Not the entire string? – Stormlight Sep 28 '17 at 12:21
  • @CodeChef123 That's right. If `s` wasn't a string literal and could be modified, you should've done `s=s1`. And don't forget to deallocate the memory for `s1` with `free(s1)`. – J...S Sep 28 '17 at 12:22
  • So you're saying the address s is pointing to is in ROM? Is there any reason for this, as it seems more logical for it to be like a normal pointer(*ints, for e.g.) – Stormlight Sep 28 '17 at 12:23
  • And for the 2nd part of my question if I remove *s=*s1 and print s1 how does the program know when to stop printing because I haven't supplied the \0 character – Stormlight Sep 28 '17 at 12:25
  • About the first part, see links in the answer I just added. About the second part, the memory adjacent to the last character probably just happened to be `0` which is equivalent to `\0` denoting the end of string. You _cannot_ rely on this as `malloc()` won't initialise the memory it allocates. But `calloc()` will initialise its memory with `0`. – J...S Sep 28 '17 at 12:28
0

In your code *s=*s1 only copy the first content of s1 into s. i.e, *(s+0)=*(s1+0) not the entire string. So we need to assign the address of s1 to s. i.e, s=s1.

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

int main()
{
    char *s = "abcdefghijklmnop", *s1=malloc(17);
    int i;
    for(i=0;i<strlen(s);i++)
    {
        *(s1+i) = *(s+strlen(s)-1-i);
    }
    s=s1;
    printf("%s",s);
    free(s1);
    return 0;
}

It is good practice to free the memory after its use.

Aashish Kumar
  • 2,771
  • 3
  • 28
  • 43