Can a string pointer in C be directly assigned a string literal? - c

The following program works fine, and I'm surprised why :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void xyz(char **value)
{
// *value = strdup("abc");
*value = "abc"; // <-- ??????????
}
int main(void)
{
char *s1;
xyz(&s1);
printf("s1 : %s \n", s1);
}
Output :
s1 : abc
My understanding was that I have to use strdup() function to allocate memory for a string in C for which I have not allocated memory. But in this case the program seems to be working fine by just assigning string value using " ", can anyone please explain ?

String literals don't exist in the ether. They reside in your programs memory and have an address.
Consequently you can assign that address to pointers. The behavior of your program is well defined, and nothing bad will happen, so long as you don't attempt to modify a literal through a pointer.
For that reason, it's best to make the compiler work for you by being const correct. Prefer to mark the pointee type as const whenever possible, and your compiler will object to modification attempts.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void xyz(char const **value)
{
*value = "abc";
}
int main(void)
{
char const *s1;
xyz(&s1);
printf("s1 : %s \n", s1);
s1[0] = 'a'; << Error on this line
}

Your program works fine because string literal "abc" are character arrays , and what actually happens while assigning a string literal to a pointer is , the compiler first creates a character array and then return the address of the first element of the array just like when we call the name of any other array.
so in your program you have passed address of a char pointer to the function xyz
and
*value = "abc";
for this statement , compiler first creates a character array in the memory and then returns its address which in turn gets stored in the char pointer.It is worth knowing that the compiler creates the char array in read only memory.Thus , the address returned refers to a const char array.Any attempt to modify its value will return it compile-time error.

You can define a string in C with char *str = "some string";, str is a pointer which points to the location of the first letter in a string.

Related

Why does this C program throw a segmentation fault at runtime?

I'm declaring character array as char* string. And then I declare other pointer which again refer to original string, then when I'm going to change any thing on that string, at runtime program throws segmentation fault.
#include <string.h>
#include <ctype.h>
int main(void)
{
char* s = "random";
char* t = s;
*t = 'R'; // ----> Segmentation fault
t[0] = toupper(t[0]); // ----> Segmentation fault
*s = 'R'; // ----> Segmentation fault
s[0] = 'R'; // ----> Segmentation fault
printf("s is : %s , address : %p \n", s,s);
printf("t is : %s , address : %p \n", t,t);
return 0;
}
even this is not working :
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(void)
{
char *p = "random";
*p = 'N'; // ----> Segmentation fault
return 0;
}
I'm declaring character array as char* string.
This is where your problems begin! Although pointers and arrays have some things in common, syntactically, they are not the same. What you are doing in the line copied below is declaring s as a pointer to a char and initializing that pointer with the address of the string literal you provide.
char* s = "random";
As a string literal, the compiler is allowed to (though not obliged to) allocate memory for that data in read-only memory; thus, when you attempt (later) to modify the character pointed to by (the address in) the s variable (or any other pointer, such as your t, which contains the same address), you will experience undefined behaviour. Some systems will cause your program to crash ("Segmentation fault"), others may silently allow you to 'get away' with it. Indeed, you may even get different result with the same code at different times.
To fix this, and to properly declare a character array, use the [] notation:
char a[] = "random";
This will declare a as a (modifiable) array of characters (whose size is determined, in this case, by the initial value you give it - 7, here, with the terminating nul character included); then, the compiler will initialize that array with a copy of the string literal's data. You are then free to use an expression like *a to refer to the first element of that array.
The following short program may be helpful:
#include <stdio.h>
int main()
{
char* s = "random";
*s = 'R'; // Undefined behaviour: could be ignored, could crash, could work!
printf("%s\n", s);
char a[] = "random";
*a = 'R'; // Well-defined behaviour - this will change the first letter of the string.
printf("%s\n", a);
return 0;
}
(You may need to comment-out the lines that use s to get the code to run to the other lines!)
"random" is a constant string literal. It is placed by OS into the protected Read-Only Memory (CPU is instructed by OS to prevent write operations in this memory).
's' and 't' both point to this protected read-only memory region.
Once you tries to write into it, CPU detects this attempt and generates exception.
you try to modify the string literal. It is an Undefined Behavoiur and everything may happen including the segfault.
from the C standard what is an UB:
—The program attempts to modify a string literal (6.4.5).

Changing the value of a string with a pointer in C

I was trying to change the value of the string t_string by passing a pointer of the string to a function and then changing the value of that pointer in the function.
The output I am receiving is the original string "Hello".
Any help would be greatly appreciated :) Thanks!
#include <stdio.h>
#include "string.h"
void editString(char *theString);
int main() {
char t_string[] = "Hello\n";
char *s = t_string;
editString(s);
printf("The string after: %s", t_string);
return 0;
}
void editString(char *theString){
theString = "Good Bye\n";
}
In C, parameters are pass by value. What you're doing is changing the value of the local variable theString to point to a string literal. That local variable change is not reflected in the calling function.
To change what theString points to, use strcpy. That will follow what theString points to (i.e. the array in main). Note however that the array isn't large enough to hold the new string, so if you do that you will write past the end of the array and invoke undefined behavior. So you need to make the array large enough to hold either string.
int main() {
char t_string[20] = "Hello\n"; // enlarge array to hold either string
char *s = t_string;
editString(s);
printf("The string after: %s", t_string);
return 0;
}
void editString(char *theString){
strcpy(theString, "Good Bye\n"); // use strcpy
}
Array designators are non-modifiable lvalues. So you can not change an array such a way.
In this statement
char *s = t_string;
there is created a new object with the name s that is initialized by the address of the first character of the array t_string.
In this call
editString(s);
there is created a copy of the value of the argument that is assigned to the function parameter.
You can imagine the function definition and its call the following way
editString(s);
//...
void editString(/*char *theString*/){
char *theString = s;
theString = "Good Bye\n";
}
So even the argument s is not changed by the function. That is at first the local variable theString initialized by the value stored in the argument s and then this local variable is reassigned by the address of the first character of the string literal "Good Bye\n".
Neither the array t_string nor the pointer s defined in main were changed in the function.
If you want to change the array you have to assign its characters individually for example by using the standard string function strcpy declared in header <string.h>. The array has to have enough size to accommodate the new string literal.
For example
#include <stdio.h>
#include "string.h"
void editString(char *theString);
int main( void )
{
char t_string[10] = "Hello\n";
char *s = t_string;
editString(s);
printf("The string after: %s", t_string);
return 0;
}
void editString(char *theString){
strcpy( theString, "Good Bye\n" );
}
Take into account that according to the C Standard the function main without parameters shall be declared like
int main( void )

C String Length using null

I know the C language has dynamic length strings whereby it uses the special character null (represented as 0) to terminate a string - rather than maintaining the length.
I have this simple C code that creates a string with the null character in the fifth index:
#include <stdio.h>
#include <stdlib.h>
int main () {
char * s= "sdfsd\0sfdfsd";
printf("%s",s);
s[5]='3';
printf("%s",s);
return 0;
}
Thus, a print of the string will only output up to the fifth index. Then the code changes the character at the fifth index to a '3'. Given my understanding, I assumed it would print the full string with the 3 instead of the null, as such:
sdfsdsdfsd3sfdfsd
but instead it outputs:
sdfsdsdfsd
Can someone explain this?
This program exhibits undefined behavior because you modify a read-only string literal. char* s = "..." makes s point to constant memory; C++ actually disallows pointing non-const char* to string literals, but in C it's still possible, and we have to be careful (see this SO answer for more details and a C99 standards quote)
Change the assignment line to:
char s[] = "sdfsd\0sfdfsd";
Which creates an array on the stack and copies the string to it, as an initializer. In this case modifying s[5] is valid and you get the result you expect.
String literals can not be changed because the compiler put the string literals into a read-only data-section (but this might vary by underlying platform). The effect of attempting to modify a string literal is undefined.
In your code:
char * s= "sdfsd\0sfdfsd"
Here, s is char pointer pointing to a string "sdfsd\0sfdfsd" stored in read-only memory, making it immutable.
Here you are trying to modify the content of read-only memory:
s[5]='3';
which leads to undefined behavior.
Instead, you can use char[]:
#include <stdio.h>
int main () {
char a[] = "sdfsd\0sfdfsd";
char * s = a;
printf("%s",s);
s[5]='3';
printf("%s\n",s);
return 0;
}
This operation has failed:
s[5] = 3;
You're trying to change a string literal, which is always read-only. My testing shows the program exited with segfault:
Segmentation fault (core dumped)
You should store it in an array (or allocated memory) before any attempts to change it:
char s[] = "sdfsd\0sfdfsd";
With the above change, the program works as intended.
#include <stdio.h>
int main(){
char x[10] = "aa\0a";
x[2] = '1';
puts(x);
printf("\n\n\nPress any key to exit...");
getch();
return 0;
}
Output: aa1a

Memory fault and pointer to string

So I'm trying to reverse a string, but I get a memory fault. Memory for s and s1 is initialized enough to accomodate the '/0' character as well.
Interestingly if I remove *s=*s1 and print s1 instead the program works.
But I haven't even set the "\0" character at the end of s1 so how does it even know where to stop printing?
And in the case below what exactly is the issue?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void main(void)
{
char *s = "abcdefghijklmnop", *s1=malloc(17);
int i;
for(i=0;i<strlen(s);i++)
{
*(s1+i) = *(s+strlen(s)-1-i);
}
*s=*s1;
printf("%s",s);
}
The char *s = "abcdefghijklmnop" is a string literal which is often in read-only memory.
An error will be generated if you attempt to modify a string literal.
You attempt to replace the first character in s with the first character in s1 when you do *s=*s+1.
If s wasn't a string literal, you should've done s=s1 instead of *s=*s1 to make s its reverse.
More about this:
https://softwareengineering.stackexchange.com/questions/294748/why-are-c-string-literals-read-only
String literals: Where do they go?
where in memory are string literals ? stack / heap?
The correct string is printed with printf("%s", s1); even if no \0 was stored because the memory next to the last character just happened to be 0 which is equivalent to \0. This needn't always be so and cannot be relied upon as malloc() doesn't initialise the memory that it allocates.
But calloc() will initialise the memory it allocates to 0.
See more here.
In your code *s=*s1 only copy the first content of s1 into s. i.e, *(s+0)=*(s1+0) not the entire string. So we need to assign the address of s1 to s. i.e, s=s1.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char *s = "abcdefghijklmnop", *s1=malloc(17);
int i;
for(i=0;i<strlen(s);i++)
{
*(s1+i) = *(s+strlen(s)-1-i);
}
s=s1;
printf("%s",s);
free(s1);
return 0;
}
It is good practice to free the memory after its use.

Change string value by address C

I'm trying to change the value of a string by passing its address to a function.
I get NULL as a result.I tried strcpy but it dosen't work for pointers on strings.
Code :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void changeStr (char ** tmpP){
char* test="Hello world !";
char** add=&test;
tmpP=add;
}
int main() {
char* tmp;
changeStr(&tmp);
printf("\n %s \n",tmp);
return 0;
}
result :
(NULL)
Currently the behaviour of your code is undefined as changeStr is a no-op, and you are attempting to call printf with the uninitialised variable tmp. That accounts for your (arbitrary) output. On other occasions the compiler might eat your cat.
add has automatic storage duration, and tmpP is the result of a value copy of &tmp from the caller. These assignments, although perfectly valid, are not visible to the calling function main().
The solution is to write
*tmpP = "Hello World";
as the only statement in changeStr.
You should note that tmp in main() will point to a read-only string literal.
What your doing is the mistake, tmpP=add; you thought that the add value will point to tmpP.
If you want to change the value of string passed to function, you can do in this way. I saw already #Bathseba pointed out.
Try this,
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void changeStr (char ** tmpP){
char* test;
char** add=&test;
*tmpP= "Hello world !";
}
int main() {
/* Here it has string cruel that pass to function*/
char* tmp="Cruel";
changeStr(&tmp);
printf("\n %s \n",tmp);
return 0;
}
Output:
Hello world !
What you did.
void changeStr (char ** tmpP){
char* test = "Hello world !";
char** add=&test;
tmpP=add; //<-- Here your assigning add to tmpP, it shouldn't.
}

Resources