How to change character in a string? [duplicate] - c

This question already has answers here:
What is the difference between char s[] and char *s?
(14 answers)
Closed 5 years ago.
I want to have a function that receives a string as a parameter and change symbols of the string
char *strChanger(char *str).
I tried to implement it like this:
char *strChanger(char *str) {
if(str[0] != '\0') {
str[0] = 'a';
}
return str;
}
In the program it should look like char *newstr = strChanger("hi");
But when I try to change a character in the string, a program chrashes.
I did some experiments and find that:
// Works fine
char str[] = "hi";
str[0] = 'a';
// Crashes
char *str = "hi";
str[0] = 'a';
I dont understand the difference. Why the second block of code doesn't work?

Because modifying string literal is undefined behavior - in your case leading to crash of your program.
In the second example, you are passing the string literal direclty and tried to make changes to it. Speaking in terms of char *newstr = strChanger("hi").
In fact char *str = "hi"; is basically making str point to the string literal. More specifically string literal is an array which is converted into pointer to the first element and which is then assigned to str. Then you tried to modify it - which is undefined behavior.
In the first case a copy of it is made which is modifiable and you can make changes to it which is then passed and it worked. You are declaring a char array and initializing it with the content of the string literal.
If you have POSIX defined "strdup" then you can do this
char *newstr = strChanger(strdup("hi"));
But again then inside strChanger you need to check the passed value - strdup may return NULL in case it fails to allocate memory and provide you with the copied string. At some point after using like this you will have to free the memory - free(newstr).
From standard 6.4.5p7 under string literal
It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined.
From 6.7.9p14 under initialization
An array of character type may be initialized by a character string literal or UTF-8 string literal, optionally enclosed in braces. Successive bytes of the string literal (including the terminating null character if there is room or if the array is of unknown size) initialize the elements of the array.

Related

Modifying string literals or char arrays with pointer arithmetic [duplicate]

This question already has answers here:
Why do I get a segmentation fault when writing to a "char *s" initialized with a string literal, but not "char s[]"?
(19 answers)
Closed 1 year ago.
I understand char* pString is read only, therefor pString[0]='A' will give a Segmentation fault, but why does pString2[0]='A' work in below code:
char* pString = "abcdefg";
char tmpStr[80];
strcpy(tmpStr, pString);
char* pString2 = tmpStr;
//pString[0] = 'A'; // gives segmentation error since string literal is read-only.
pString2[0] = 'A'; // why this one works?
pString2 is not pointing to a string literal. It's pointing to the first element of a char array, and that array is not const, so writing to it is allowed.
In this declaration
char* pString = "abcdefg";
the string literal is the record "abcdefg" not the declared pointer.
The string literal in C has the type char[8]. Though in the type there is absent the qualifier const nevertheless you may not change a string literal. Any attempt to change a string literal results in undefined behavior.
In C++ opposite to C string literals have types of constant character arrays.
As for the declared pointer then it points to the first element of the string literal.
In this code snippet
char tmpStr[80];
strcpy(tmpStr, pString);
there is declared character array tmpStr. You may change the array.
In this statement
strcpy(tmpStr, pString);
elements of the string literal are copied in the character array.
And in the declaration below the declared pointer point to the first element of the array.
char* pString2 = tmpStr;
pString2[0] = 'A';
So you may change the array. You could use even the pointer pString instead of pString2 like
pString = tmpStr;
pString[0] = 'A';
Pay attention to that you may initialize a character array with a string literal. So you could write for example
char tmpStr[] = "abcdefg";
*tmpStr = 'A';
or
tmpStr[0] = 'A';

strcat not working when trying to add a string and a char?

One of the first times I'm using C. I can't append the string every time I encounter a capital letter. I understand that this is very simple in most languages but I am trying to learn it in C.
string s = get_string();
string s1 = "";
for (int i = 0, n = strlen(s); i < n; i++)
{
if (s[i] >= 'A' && s[i] <= 'Z')
{
strcat (s1,s[i]);
}
}
-shudders- I now have two reasons to boycott CS50.
It appears to be teaching you to use an unsuitable storage duration.
It's teaching you to use an unsuitable type alias.
C11/7.1.1p1 tells us that a variable declared with this typedef can meaningfully store a pointer to a string (a pointer to a string is "a pointer to its initial (lowest addressed) character") if it points at an object storing a sequence of values fitting a very specific pattern (a string is "a contiguous sequence of characters terminated by and including the first null character").
You need to pass a pointer to a modifiable string as the first argument of strcat. As it currently stands, you're passing a pointer to a string literal as the first argument, and as others have said this causes undefined behaviour.
Here's a modifiable string:
char str[128] = "hello";
Actually, there are 127 modifiable strings there, and they have pointers to strings like this:
str + 0 or &str[0] points at the first
str + 1 or &str[1] points at the second
and so on up until
str + 126 or &str[126] points at the 127th
str + 127 or &str[127] points at a 128th, but you can't change this (empty) string without accessing str out of bounds and causing undefined behaviour.
You can call fgets(str, 128, stdin) to obtain a string, which likely contains a newline ('\n') character (if it doesn't, then the line is incomplete)... Strip the newline with str[strcspn(str, "\n")] = '\0'; and then you can use strcat(str, (char[]){s[i], '\0'});... providing you don't overflow the array.
strcat is defined like this: char *strcat(char *dest, const char *src); which means that it can only concatenate two strings with eachother. What you can do (in modern C) is this:
strcat(s1, (char[]){s[i], '\0'});
You have another problem though; s1 is a string literal. It is undefined behavior trying to concatenate it with another string. You will either have to make an array or allocate it on the heap to use it correctly.
char s1[128];
or
char* s1 = malloc(128);
Notice that those implementations cannot hold strings larger than 127 characters, and you have to add NUL termination yourself.

how to point a pointer to string without declaring string directly [duplicate]

This question already has answers here:
What is the difference between char s[] and char *s?
(14 answers)
Closed 6 years ago.
#include <stdio.h>
int main(){
char *ch = "Hello, World";//character pointer pointing to a string without declaration.
printf("%s", ch);//printing the string without <i>dereferencing</i> it.
}
I saw an example in a book, with code as given above. I don't understand how a character pointer points to a string without declaring a string first.Also there is no dereference operator used to print the string.
As stated very well by #tryurbest, Why it works with pointers:
When you say char * ch in C, you are allocating a pointer in the memory. When you write char *ch = "Hello, World";, you are creating a string literal in memory and making the pointer point to it. When you create another string literal "new string" and assign it to ch, all you are doing is changing where the pointer points.
On the other hand, for added information, Why it doesn't work with arrays:
When you say char ch1 [] = "Hello, World", you are creating a string literal and putting it in the array during its definition. It is ok to not give a size, as the array calculates it and appends a '\0' to it. You cannot reassign anything to that array without resizing it.
Hope this helps to clarify some things.
"Hello, World" is a string literal or read only memory store in data block. A variable ch is pointer to char, which is initialized with the location of the first character.
That's simply how printf works with a const char* argument. (Your pointer actually points to const data.)
Starting at the memory location denoted by the pointer, it prints character by character until a NUL terminator is reached.
The C standard library string functions all work in this way. Simply put it's how the language models strings.

C string assignment gives segmentation fault [duplicate]

This question already has answers here:
Why do I get a segmentation fault when writing to a "char *s" initialized with a string literal, but not "char s[]"?
(19 answers)
Closed 7 years ago.
I am new to C and I want perform this task: declare and initialize a string and then reassign each string element to a new value.
Writing the code in this way:
char *str = "geeksforgeeks\0";
for (int i = 0; str[i] != '\0'; ++i) {
str[i] = 'a';
}
throws a segmentation fault.
But if I write the code in this manner:
char string[] = "geeksforgeeks\0";
char *str = string;
for (int i = 0; str[i] != '\0'; ++i) {
str[i] = 'a';
}
the program behaves correctly.
Also this code:
char str[] = "geeksforgeeks\0";
for (int i = 0; str[i] != '\0'; ++i) {
str[i] = 'a';
}
behaves correctly.
What is the difference between the two? Should't be equivalent?
char *str = "geeksforgeeks\0";
This string is allocated in readonly* memory and you can't modify it. Also the null terminator there is redundant.
Same is not the case with the array you defined, that is why it works. In the case with array the string literal is copied to memory where array resides - and you can modify contents of that array. So using this
char *str = string;
you point to the first element of the array - which as mentioned, is modifiable (as well as all elements of the array).
*It can be they are stored not in read only memory, depends on platform. But anyway you are not allowed to modify them.
If you have:
char *str = "geeksforgeeks\0";
the string is (usually) stored in read-only memory and you get a segmentation fault when you try to modify it. (The \0 is really not needed; you have two null bytes at the end of the string.)
The simplest fix is to use an array instead of a constant string (which is basically what you do in the second working case):
char str[] = "geeksforgeeks";
Note that you should really use this for the string since the string is not modifiable:
const char *str = "geeksforgeeks";
The reason is simple.
In first example, you have a pointer to an static string. that's why you get a segmentation fault.
char *str = "Test";
This is practically a constant string. But in 2nd example, it is a variable that you change.
// You have a variable here
char str_array[] = "Test";
// Now you have a pointer to str_array
char *str = str_array;
You’ve hit on a bit of ugly legacy baggage. When you write the literal "geeksforgeeks\0", the compiler turns that into a pointer to an array of characters. If you later use the string "geeksforgeeks\0" again, it’s allowed to point both references to the same array. This only works if you can’t modify the array; otherwise, fputs(stdout, "geeksforgeeks\0"); would be printing aeeksforgeeks. (Fortran can top this: on at least one compiler, you could pass the constant 1 by name to a function, set it equal to -1, and all your loops would then run backwards.) On the other hand, the C standard doesn’t say that modifying string literals won’t work, and there’s some old code that did. It’s undefined behavior.
When you allocate an array to hold the string, you’re creating a unique copy, and that can be modified without causing errors elsewhere.
So why aren’t string literals const char * instead of char *? Early versions of C didn’t have the const keyword, and the standards committee didn’t want to break that much old code. However, you can and should declare pointers to string literals as const char* s = "geeksforgeeks\0"; so the compiler will stop you from shooting yourself in the foot.

Simple modification of C strings using pointers

I have two pointers to the same C string. If I increment the second pointer by one, and assign the value of the second pointer to that of the first, I expect the first character of the first string to be changed. For example:
#include "stdio.h"
int main() {
char* original_str = "ABC"; // Get pointer to "ABC"
char* off_by_one = original_str; // Duplicate pointer to "ABC"
off_by_one++; // Increment duplicate by one: now "BC"
*original_str = *off_by_one; // Set 1st char of one to 1st char of other
printf("%s\n", original_str); // Prints "ABC" (why not "BBC"?)
*original_str = *(off_by_one + 1); // Set 1st char of one to 2nd char of other
printf("%s\n", original_str); // Prints "ABC" (why not "CBC"?)
return 0;
}
This doesn't work. I'm sure I'm missing something obvious - I have very, very little experience with C.
Thanks for your help!
You are attempting to modify a string literal. String literals are not modifiable (i.e., they are read-only).
A program that attempts to modify a string literal exhibits undefined behavior: the program may be able to "successfully" modify the string literal, the program may crash (immediately or at a later time), a program may exhibit unusual and unexpected behavior, or anything else might happen. All bets are off when the behavior is undefined.
Your code declares original_string as a pointer to the string literal "ABC":
char* original_string = "ABC";
If you change this to:
char original_string[] = "ABC";
you should be good to go. This declares an array of char that is initialized with the contents of the string literal "ABC". The array is automatically given a size of four elements (at compile-time), because that is the size required to hold the string literal (including the null terminator).
The problem is that you can't modify the literal "ABC", which is read only.
Try char[] original_string = "ABC", which uses an array to hold the string that you can modify.

Resources