0

I am trying to remove the white spaces at the end of a string. I have the following code:

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

char *trim(char *str) {
   char *end;
   end = str + strlen(str) - 1;
   while(end > str && isspace((unsigned char)*end)) {
      end--;
   }
   *(end++) = '\0'; //this line causes the segfault
   return str;
}

int main(void) {
   char *str = "mystring  ";
   printf("before trim string is %s\n", str);
   printf("length before: %d\n", strlen(str)); //should be 10
   str = trim(str);
   printf("after trim string is %s\n", str);
   printf("length after: %d\n", strlen(str)); //should be 8
   return 0;
}

When I run the code, I get a segmentation fault. What I'm not sure about is why incrementing the pointer 'end' by 1, and then changing the value it points to from a white space to the null terminator causes the segfault. I have read that incrementing a pointer in C such that the pointer does not point to an element of an array is undefined behaviour. However, wouldn't the white spaces at the end of "mystring" still be part of the char array str[]? Any help is really appreciated.

1
  • 1
    Because the string constant "mystring " is constant. Try using it to initialize a modifiable array: char str[] = "mystring ". Commented Jul 25, 2018 at 3:04

3 Answers 3

2

The issue here is that the line causing the crash is attempting to modify a string literal, which results in undefined behavior.

According to https://en.cppreference.com/w/c/language/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.

You'll have to make sure to pass a char* to a modifiable array, such as one you allocate yourself with malloc().

Sign up to request clarification or add additional context in comments.

Comments

1

The other responses are correct - but i'm surprised your compiler did not pick up the error. Below compiles and runs fine with Visual Studio 2017.

Note a little bug also in trim()

*(++end) = '\0'; NOT
*(end++) = '\0';

All good now.

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

char *trim(char *str) {
    char *end;
    end = str + strlen(str) - 1;
    while (end > str && isspace((unsigned char)*end)) {
        end--;
    }
    *(++end) = '\0'; //this line causes the segfault
    return str;
}

int main(void) {
    char str0[] = "mystring  "; // minor change here
    char *str = str0;           // minor change here
    printf("before trim string is %s\n", str);
    printf("length before: %d\n", strlen(str)); //should be 10

    str = trim(str);
    printf("after trim string is %s\n", str);
    printf("length after: %d\n", strlen(str)); //should be 8
    return 0;
}

2 Comments

What is the difference between using *(++end) over *(end++)?
In the case of (++end) the end pointer is incremented before the operation of setting the value to '\0'. In the case of (end++) the end pointer is incremented AFTER the operation of setting the value to '\0'. When you reach this line the end pointer is at letter 'g' of string. The way you had it would give length 7 (mystrin) instead of 8 (mystring). :-)
1

When a string is processed with a pointer, the compiler assigns the storage address of the first character of the constant string after "=" to the pointer, and the constant string exists in the read-only memory. You can try these two code to observation difference:

int main()
{
    char str[] = "abcd";
    *str = 'c';
    printf("%s\n", str);
    return 0;
}

int main()
{
    char *str = "abcd";
    *str = 'c';    // error
    printf("%s", str);
    return 0;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.