3

I've been trying to change upper case letters to lower case letter using pointers but I keep getting segmentation faults. Here is my source code:

#include <stdlib.h> #include <string.h> char *changeL(char *s); char *changeL(char *s) { char *upper = s; for (int i = 0; upper[i] != '\0'; i++) { if (upper[i] >= 'A' && upper[i] <= 'Z') { upper[i] += 32; } } printf("%s\n", upper); return upper; } int main() { char *first; char *second; first = "HELLO My Name is LoL"; printf("%s\n", first); second = changeL(first); printf("There is no error here\n\n"); printf("%s\n", second); return 0; } 

Using gdb I found the seg fault to be in "upper[i] += 32;". I don't understand why the seg fault is there.

0

3 Answers 3

5

"HELLO My Name is LoL" is the constant memory. You can`t change it. However you pass pointer to this memory(first) to a function which tries to change it. Thus you got segmentation fault. You should copy this string to memory butffer. Like

char buffer[] = "HELLO My Name is LoL"; 

and then pass buffer to changeL

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

4 Comments

So creating a copy of the pointer doesn't matter because you can't modify pointers?
you cant change const memory. Both "HELLO My Name is LoL" and first variable have the same address. You can print it with printf("%p", "HELLO My Name is LoL") and printf(%p, first); It does not matter how many times do you copy the address. You just cant change data laying on this address, cause its const
Thanks ! This has been breaking my head for a few hours now.
Detail: ""HELLO My Name is LoL" is the constant memory" is not quite certain. Attempting to write first[] might work, it might not, it might crash code. It is undefined behavior. C does not require constant memory even if it is const.
3

A couple of notes in addition to what @Alex correctly points out in his answer. First

char *changeL(char *s); char *changeL(char *s) { .... } 

There is no need for a prototype before the function if the function is one line below. A prototype is used to inform code below it that the function described by the prototype exists and is defined elsewhere. If you define the function immediately below the prototype it makes the prototype irrelevant.

Second as noted in Alex's answer, on a overwhelming majority of systems, a String Literal, e.g. the "Something Here" in char *s = "Something Here"; is immutable and resides in read-only memory and any attempt to modify the string literal generally results in a SegFault.

Instead you need to create an array of characters which can be modified, e.g.

char first[] = "HELLO My Name is LoL"; 

or with C99+ you can use a Compound Literal to initialize first as a pointer to an array of char, e.g.

char *first = (char[]){ "HELLO My Name is LoL" }; 

In both cases above the characters pointed to by first will be modifiable.

Addition Per Comment

"can you also explain to him why is he getting segfault at upper[i] += 32;" 

Yes. At mentioned above, when you initialize a pointer to a String Literal on virtually every current system (ancient systems had no distinction or protection for read-only memory -- all memory was writable). In the current day, creating a string literal (e.g. "foo") creates the string in memory which cannot be modified. (for ELF executables, that is generally in the .rodata section of the executable -- dissecting closer ".ro...data" meaning "read-only data")

When any attempt is made to change data that cannot be modified, a Segmentation Fault generally results because you have attempted to write to an address within a segment that is read-only. (thus the Segmentation Fault -- of SegFault)

In the code above as originally written with

first = "HELLO My Name is LoL"; 

If you compile to assembly (on Linux, e.g. gcc -S -masm=intel -o mysaved.asm myfile.c you will see that the string "HELLO My Name is LoL" is in fact created in the .rodata section. You do not have any ability to change that data -- you now know what happens when you try :)

The code as written in the Question also shows confusion about what the pointers first and second actually point to. By assigning the return of changeL to second, there is no new memory created for second. It is no different than simply assigning second = first; in main(). second is just a separate pointer that points to the same memory referenced by first. A more concise version of the code would be:

#include <stdio.h> void changeL (char *s) { for (int i = 0; s[i]; i++) if (s[i] >= 'A' && s[i] <= 'Z') s[i] += 32; } int main (void) { char first[] = "HELLO My Name is LoL"; char *second = first; printf("%s\n", first); changeL(first); printf("%s\n", second); return 0; } 

(note: both header files in the original code are unnecessary, <stdio.h> is the only required header)

To illustrate second simply points to first:

Example Use/Output

$./bin/chars HELLO My Name is LoL hello my name is lol 

7 Comments

Good answer, but can you also explain to him why is he getting segfault at upper[i] += 32;.
Was playing with intel and at&t assembly output and they seem to be exactly the same. So is this standard that compiler has to allocate read only memory?
The basic explanation is the compiler has to stuff constant literals somewhere, and those things that can't be changed go in the read-only section. The full explanation has to do with compiler optimizations and whether, for example, if "Hello World" appears more than once in your code, the compiler can store that literal only once and use a single stored reference for ever time "Hello World" appears in your program. The key is a string literal "Hello World" is just like literal integer constant 1. You can't change either.
is it possible to use other dialects except att and intel in gcc?
Not that I know of, you either get the default ATT or you use intel. Last time I read man gcc I think those were you only two choices. Yep still is "Supported choices are intel or att" :)
|
0

This code outputs inly the lower case in string

#include<stdio.h> #include<string.h> int main() { char b[50]; printf("String="); scanf("%[a-z]",b); printf("%s",b); return 0; } 

1 Comment

This does not really answer the question. This does not convert the uppercase to lowercase.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.