Segmentation fault error

After 2 years was need to switch back to C again for small project. Now am doing some C excersises and here is a problem.
Need to write a function which replaces every occurrence of "foo" by "xxx". ex, "food fool" -> "xxxd xxxl".

here is my code:

void censor(char *a){
    while (*(a+2)) {
        if (*a == 'f' && *(a+1)=='o' && *(a+2)=='o') *a=*(a+1)=*(a+2)='x';
        a++;
    }
}

int main(void)
{
    char *a = "hello foo";
    
    censor(a);
    printf("%s",a);

  return 0;
}

after compilation am getting segmentation fault.
Tried online C compiler and also Xcode IDE.

Eventually this literal resides in a const segment and cannot be edited in place.

1 Like

Try with char a[] = "hello foo"; then the array is stored in a memory location you can modify

You should check the length of your parameter before doing the while as if it’s a very short string (a+2) might be already pointing beyond the trailing null char

1 Like

Tried with char same issue segmentation fault.

Tried with checking by chaining
*a&&*(a+1)&&*(a+2)in a while with same issue. Also tried declaring a as array before giving to function. And btw same code was working 3 years ago cos i did this excersise and saved the solution but now even copy pasting whole code in IDE its giving that error. Can anyone try on their machine? Im using macbook before was working on windows . Thanks

Which controller/board do you use?

Thanks to both of you. Tried just now modifying a bit the code now it works.

void censor(char *str) {
    char *c = str;
    while (*(c+++2)) if (*c == 'f' && *(c+1) == 'o' && *(c+2) == 'o') *c = *(c+1) = *(c+2) = 'x';
}

and string declared with char array not pointer to read only section.

Now can move forward for more excersises.

Offtop: Like old version of this forum more than this one :frowning:

Your compiler should have warned you about this error:

warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
     char *a = "hello foo";
               ^

If it didn't, please make sure you have all your warnings enabled.

So how can a multi-character literal be declared as C-style char[] instead of a C++ String type? The String type is a nogo on ATmega chips and others with very limited RAM capacity!

This was answered here:

Do keep in mind that if a is a local variable, you will end up with two copies of the string in RAM: one for the read-only string literal, and one local copy in the array a. Every time you call the function, the string will be memcpy'd into the local array a.

No, it's not answered. The problem resides in the type of the literal "hello foo".

I'd expect something like extern "C" that excludes the non-C String type.

I'm not sure what you mean. I never mentioned the Arduino String type at all.
This is just about string literals, arrays of characters and pointers to them.

The code char a[] = "foo" is just a plain array of characters (in both C and C++), it has nothing to do with the String data type.

As a side note, writing to string literals in C is not allowed either, although C compilers are not as vocal about it as C++ compilers. With a C compiler, it'll just crash at run-time.

The type of a string literal in C is char[] and the type of a string literal in C++ is const char[]. Even though the type is non-const in C, trying to modify it is undefined behavior, and will probably segfault as observed in this thread.

Me2 - dunno how I mixed in the String type :frowning:

So the difference between C and C++ is the const attribute that correctly applies to string literals.

I would disagree with the statement that in C string literal is char ch.
Char ch is array with each element equal to the size of char for current hardware.
I.e. inside is {‘x’,’x’,’x’’\0’} which is not string literal its array of chars with last element containing null terminating char.

On the other hand const char ch is same thing except compiler wont allow to modify it its just read only array.

Char *ch =“hello world” is “hello world” written somewhere in memory with consecutive addresses h+e+l+etc and ‘\0’ at the end. Which has its first address assigned to pointer of type char. I.e. ch[0] is pointing to memory location containing that h. In this case hello world is string literal. But pointer can be changed to be assigned somewhere else in the memory anytime.

Const char *c is pointer that cant be assigned anything but where it was asigned to point at the time of declaration.

In my first post there was a workaround to make function work even with char *p if i would dynamicaly allocate memory for char *p and fill it with characters then give it to function to modify it.

@PieterP i switched from swift to C for small project and with swift xcode was giving me errors i needed but when compiling c with xcode its not as informative as gcc may be have to get into preferences and figure out if i have to enable some checks.

From the C11 standard:

In translation phase 7, a byte or code of value zero is appended to each multibyte
character sequence that results from a string literal or literals.) The multibyte character
sequence is then used to initialize an array of static storage duration and length just
sufficient to contain the sequence. For character string literals, the array elements have
type char, and are initialized with the individual bytes of the multibyte character
sequence.

[...]

the declaration

char *p = "abc";

defines p with type ‘‘pointer to char’’ and initializes it to point to an object with type ‘‘array of char’’ with length 4 whose elements are initialized with a character string literal. If an attempt is made to use p to modify the contents of the array, the behavior is undefined.

No, const char *c is a mutable pointer that points to an immutable character (i.e. the pointer cannot be used to modify the character). You can reassign the pointer to point to a different character without issues.

A pointer that cannot be reassigned would be char *const c.

1 Like

Yes, AFAIK, that's the most important difference, I'm not familiar with all subtleties in the C standard, so there might be other differences.

Thats why I love this forum :slight_smile: answers from long time members are amazing.

Turns out in context of literal immutability char *p=“abc” and const char *p=“abc” are equal. I cant mutate “abc” because its mutable but i can reassign *p to anything else i mean char type?

char *q = "abc";
// C:   compiles without warnings, but bad practice
// C++: compiles with warning, bad practice
q = "def"; // no problem reassigning in C (warning in C++)
q[0] = 'A'; // compiles, but crashes at runtime
const char *p = "abc";
// Okay in both C and C++
p = "def"; // no problem reassigning the pointer
p[0] = 'A'; // compilation error (good, prevents crash at runtime)
const char *const r = "abc";
// Okay in both C and C++
r = "def"; // compilation error
r[0] = 'A'; // compilation error

the reference does state

Attempting to modify a string literal results in undefined behavior : they may be stored in read-only storage

it's enforced by GCC on an ESP, it's not on a UNO (last I tried which is some time ago already)

That's because you cannot flag regions as read-only on an Arduino UNO: it doesn't have an MMU (memory management unit) or even an MPU (memory protection unit). The read-only memory it has is in a different address space than ordinary RAM, which means that the compiler cannot place constants in read-only memory for you.
If you want true read-only constants on an UNO, you need to place them there yourself using the PROGMEM attribute, but you have to remember to use the right load instructions every time you access the data (LPM or the read_pgm_* macros).

On an ESP32, the read-only flash memory is in the same address space as RAM and you can use the same load instructions regardless of what region it is in. This allows the compiler to place constants in flash without any consequences for the rest of the program. The ESP32 also has MPUs and MMUs, so you can mark certain memory regions as read-only.
If you try to write to such a read-only memory location, you are met with Guru Meditation Error: Core 1 panic'ed (LoadStoreError). Exception was unhandled.