-2

I am trying to perform a simple string manipulation (strcat) on a char array. I tried 2 approaches.

In the first case, I am allocating memory to a char* and then assigning the value through scanf() . This approach is working fine.

void fun1(char** s1) {
    char temp[15] = "&Superman";
    printf("inside fun1 %s %s\n",(*s1),temp);
    strcat((*s1),temp);
}

int main()
{
    char *str;
    str = malloc(sizeof(char)*15);
    scanf("%s",str);
    fun1(&str);
    printf("1st string %s\n",str);

    return 0;
}

The O/p is as expected for this case

Batman
inside fun1 Batman &Superman
1st string Batman&Superman

In the second approach , I am assigning value to str directly in the main() without scanf().

void fun1(char** s1) {
    char temp[15] = "&Superman";
    printf("inside fun1 %s %s\n",(*s1),temp);
    strcat((*s1),temp);
}

int main()
{
    char *str;
    str = malloc(sizeof(char)*15);
    str = "Batman";
    fun1(&str);
    printf("1st string %s\n",str);

    return 0;
}

In this case I am getting segmentation fault inside fun1() while strcat is getting executed.

inside fun1 Batman &Superman
Segmentation fault (core dumped)

GDB o/p from OnlineGDB

(gdb) r                                                                           
Starting program: /home/a.out                                                     
inside fun1 Batman &Superman                                                      

Program received signal SIGSEGV, Segmentation fault.                              
__strcat_sse2_unaligned ()                                                        
    at ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S:666                    
666     ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S: No such file or direc
tory.                                                                             
(gdb) bt                                                                          
#0  __strcat_sse2_unaligned ()                                                    
    at ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S:666                    
#1  0x00000000004006a3 in fun1 (s1=0x7fffffffebd8) at main.c:9                    
#2  0x00000000004006e4 in main () at main.c:17                                    
(gdb)             

I am confused because the string "Batman" is able to get printed inside fun1() , but its strcat is failing eventhough I am doing the same thing for both the cases.

Thanks in advance for any help.

battyman17
  • 65
  • 6
  • https://stackoverflow.com/questions/5464183/modifying-string-literal , you cannot modify string literals. – rafix07 Jan 27 '20 at 07:12
  • Also your first code invokes undefined behaviour because you only allocate 15 bytes while you need 16 to hold your resulting string including nul-terminator. – Gerhardh Jan 27 '20 at 07:16
  • 1
    Why do you allocate memory at all in second code? You discard the address immediately causing a memory leak. – Gerhardh Jan 27 '20 at 07:17
  • @Gerhardh Yeah my bad. I was just trying out stuffs. – battyman17 Jan 27 '20 at 07:27

1 Answers1

3

When you do

str = "Batman";`

str no longer points to the malloc'ed memory. It point to the string literal "batman". So you are not allowed to concatenate the other string.

A way to see this is to add some simple printing - try:

char *str;
str = malloc(sizeof(char)*15);
printf("%p\n", (void*)str);
str = "Batman";                // str now points to a different location
printf("%p\n", (void*)str);

Use strcpy instead:

str = malloc(sizeof(char)*15);
strcpy(str, "Batman");

NOTICE: You assign too little memory for the concatenation of "Batman" and "&Superman". The first is 6 char, the second is 9 char so you need 6+9+1 = 16 char. The last +1 is for holding the string termination character, i.e. \0. So besides using strcpy, you also need to allocate 16 chars.

BTW:

  • You don't need to pass the address of str to the function as the function never do any assignments like *s1 = ... something... Just pass str

  • sizeof(char) is always 1 so you don't need to write it.

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
  • Ok I get it. We cannot change literals. But the 2nd point you have made regarding no need to pass address of `str` ,I am a bit confused. Isn't `strcat` is making changes to our string? – battyman17 Jan 27 '20 at 07:25
  • 1
    @battyman17 yes, `strcat` change the string - or in other: it changes the memory that the **pointer points to** but it **does not** change the pointer! Consequently you don't need to pass "address of pointer" – Support Ukraine Jan 27 '20 at 07:30
  • Do we need check `malloc()` return value `if (str)` to see memory allocation successful and not? and also `free()` before program return. – EsmaeelE Jan 27 '20 at 07:47
  • 1
    @EsmaeelE You shall always check the value returned by `malloc`. When the program returns, you don't need to `free` as it will happen automatically when the program terminates. However, many consider it a good habit to to do an explicit call of `free` – Support Ukraine Jan 27 '20 at 08:46
  • @EsmaeelE Se https://stackoverflow.com/questions/48430891/should-you-free-at-the-end-of-a-c-program and https://stackoverflow.com/questions/5612095/is-freeing-allocated-memory-needed-when-exiting-a-program-in-c – Support Ukraine Jan 27 '20 at 09:18
  • @EsmaeelE C programms do NOT free memory on termination. The operating system may or may not do so when a process ends. And yes, there are systems out there that do not. Windows/Unix systems do clean up after bad programms. – Goswin von Brederlow Jan 27 '20 at 11:53
  • @GoswinvonBrederlow OK and thanks, beside 4386427 links I find this that explain importance of freeing memory. https://stackoverflow.com/questions/2213627/when-you-exit-a-c-application-is-the-malloc-ed-memory-automatically-freed – EsmaeelE Jan 27 '20 at 12:17