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

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';

Related

Why pointers can't be used to index arrays? [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 3 years ago.
I am trying to change value of character array components using a pointer. But I am not able to do so. Is there a fundamental difference between declaring arrays using the two different methods i.e. char A[] and char *A?
I tried accessing arrays using A[0] and it worked. But I am not able to change values of the array components.
{
char *A = "ab";
printf("%c\n", A[0]); //Works. I am able to access A[0]
A[0] = 'c'; //Segmentation fault. I am not able to edit A[0]
printf("%c\n", A[0]);
}
Expected output:
a
c
Actual output:
a
Segmentation fault
The difference is that char A[] defines an array and char * does not.
The most important thing to remember is that arrays are not pointers.
In this declaration:
char *A = "ab";
the string literal "ab" creates an anonymous array object of type char[3] (2 plus 1 for the terminating '\0'). The declaration creates a pointer called A and initializes it to point to the initial character of that array.
The array object created by a string literal has static storage duration (meaning that it exists through the entire execution of your program) and does not allow you to modify it. (Strictly speaking an attempt to modify it has undefined behavior.) It really should be const char[3] rather than char[3], but for historical reasons it's not defined as const. You should use a pointer to const to refer to it:
const char *A = "ab";
so that the compiler will catch any attempts to modify the array.
In this declaration:
char A[] = "ab";
the string literal does the same thing, but the array object A is initialized with a copy of the contents of that array. The array A is modifiable because you didn't define it with const -- and because it's an array object you created, rather than one implicitly created by a string literal, you can modify it.
An array indexing expression, like A[0] actually requires a pointer as one if its operands (and an integer as the other). Very often that pointer will be the result of an array expression "decaying" to a pointer, but it can also be just a pointer -- as long as that pointer points to an element of an array object.
The relationship between arrays and pointers in C is complicated, and there's a lot of misinformation out there. I recommend reading section 6 of the comp.lang.c FAQ.
You can use either an array name or a pointer to refer to elements of an array object. You ran into a problem with an array object that's read-only. For example:
#include <stdio.h>
int main(void) {
char array_object[] = "ab"; /* array_object is writable */
char *ptr = array_object; /* or &array_object[0] */
printf("array_object[0] = '%c'\n", array_object[0]);
printf("ptr[0] = '%c'\n", ptr[0]);
}
Output:
array_object[0] = 'a'
ptr[0] = 'a'
String literals like "ab" are supposed to be immutable, like any other literal (you can't alter the value of a numeric literal like 1 or 3.1419, for example). Unlike numeric literals, however, string literals require some kind of storage to be materialized. Some implementations (such as the one you're using, apparently) store string literals in read-only memory, so attempting to change the contents of the literal will lead to a segfault.
The language definition leaves the behavior undefined - it may work as expected, it may crash outright, or it may do something else.
String literals are not meant to be overwritten, think of them as read-only. It is undefined behavior to overwrite the string and your computer chose to crash the program as a result. You can use an array instead to modify the string.
char A[3] = "ab";
A[0] = 'c';
Is there a fundamental difference between declaring arrays using the two different methods i.e. char A[] and char *A?
Yes, because the second one is not an array but a pointer.
The type of "ab" is char /*readonly*/ [3]. It is an array with immutable content. So when you want a pointer to that string literal, you should use a pointer to char const:
char const *foo = "ab";
That keeps you from altering the literal by accident. If you however want to use the string literal to initialize an array:
char foo[] = "ab"; // the size of the array is determined by the initializer
// here: 3 - the characters 'a', 'b' and '\0'
The elements of that array can then be modified.
Array-indexing btw is nothing more but syntactic sugar:
foo[bar]; /* is the same as */ *(foo + bar);
That's why one can do funny things like
"Hello!"[2]; /* 'l' but also */ 2["Hello!"]; // 'l'

Queries on declaring & initialising string and also string memory region [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)
What is the difference between char s[] and char *s?
(14 answers)
Closed 3 years ago.
My question comes in three part.
char str[] = "hello!";
char *str1 = "heello!";
puts(str);
str1[1] = 1
puts(str1);
printf("%s\n", str1);
printf("%p\n", str1);
Ouput of code:
hello!
h1ello!
heello!
0x10735ef9b
1) I understand that when you're declaring a char * type, you're declaring a pointer that points to char type. And usually for pointer, since it contains the address of the variable its pointing to, when you print the pointer itself, you'll get the address stored in the pointer and only when you dereference the pointer, then you'll get the content stored in the variable the pointer is pointing to.
However for a char * type, why is it that it doesn't function like a regular pointer? You can print the content of the variable which the 'char *' pointer is pointing to without dereferencing it and also use it like a string variable(rather than a pointer) by changing the value of the str1[1] as shown above.
2) I was taught that you shouldn't declare a pointer variable as such in the topic of pointer:
char *str1 = "heello!";
because the pointer variable would be pointing to whatever address happens to be in the memory at that time, thus running a risk of changing the value in a memory location that you don't mean to and resulting in segfault.
Hence you should do the following:
char *str1;
char c;
str1 = &c;
*addr = "hello!"
By doing the above, you'll make sure that your pointer is pointing to the right location before dereferencing and writing to the location.
However in the notes on string, it says to declare and initialise as such:
char *str1 = "heello!";
I'm quite confused as to what I should follow now when declaring a char * pointer. Please help.
3) It says in my notes that the location of string is stored in a read only region of the memory called the text region.
Hence doing this:
char *str1 = "hello!";
str[1] = '.';
Will crash your program.
But when you do this:
char str2[7] = "hello!";
str2[1] = '.';
This is okay and will successfully change the second element in the string from 'e' to '.'
The explanation to this was that str1 points to a read only region in the memory, while str2 contains a copy of the string on the stack.
I do not understand how the above 2 different ways of declaring the string variable will make such a big difference when executing the code. Please help.
Thank you!
String literals like "heello!" are really read-only arrays of characters (including the string null-terminator).
With
char *str1 = "heello!";
you make str1 point to the first character of such an array.
And when you do str1[1] = 1 you attempt to modify the read-only array, which is forbidden and leads to undefined behavior (which can but doesn't have to lead to crashes).
That's why you either should use your own arrays for strings, or use const char * to point to literal strings.

How to change character in a string? [duplicate]

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.

Bus error 10 in C: string literals [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.
Can someone explain why
char *s1 = "abcd";
char *s2 = s1;
s1[0] = "z";
s1[2] = "\0";
gives me a bus error 10 BUT
char s1[] = "abcd";
char *s2 = s1;
s1[0] = "z";
s1[2] = "\0";
doesn't?
are char *s1 and char s1[] not equivalent? Please explain, thanks.
Be free (of historical lazyness), be wise! Pointers are not arrays! Tutorials have lied you!
In the first example, you're modifying a pointer to a constant string literal, and that's undefined behaviour. Anything can happen then!
Meanwhile, in the second case, the string itself is stored inside the array, and the array itself is in the stack. Thus, the second example exposes more than a plain innocent array that's modifiable.
The s2 pointers make no difference in all this. IMHO, the fact that the first case is compilable is just historical lazyness, otherwise known as backwards compatibility.
BTW: Are you assigning string literals to chars? That's undefined behaviour too!
In the first case you set a s1 pointer to the address const string. Const string are stored in read -only area and you cannot modify it. This means that you cannot modify a character s[x]. It is UB
In the second case you declare a local array inited with a string. In this case only the init value is read-only and after init you use an allocated array that can be modified.

Why the following code can't modify the string in array of pointers? [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)
Is modifying a string pointed to by a pointer valid?
(9 answers)
Closed 9 years ago.
I am trying to modify string "hello" to "Hello" but it's not working,neither it gives any error .Can someone please explain why it's not working.
#include <stdio.h>
int main() {
char *arr[] = {"hello" , "world"};
char **p = arr;
printf("%s\n",arr[0]);
*(*(p+0)+1) = 'H';
printf("%s\n",arr[0]);
return 0;
}
string literals are of type char[] and are stored in read only memory. You cannot alter them.
If you want to alter them you need to create a char array. What you have a is an array of pointers.
You can do this:
char foo[] = "Hello";
foo[0] = 'G';
printf("%s", foo);
Because you can't modify string literals (despite them being of an array type of non-const char). Your program invokes undefined behavior as-is.
char *arr[] = {"hello" , "world"};
arr is array of pointers to char, so you cannot modify the string literals, the pointers are pointing to.
char arr[][6] = {"hello" , "world"};
arr is 2 dimensional array of chars - or array of two strings. You can modify them, but you need to specify the length of the second dimension of the array. It needs to be big enough to hold the longest strings.

Resources