Pass string literal as char* via argument - c++

I made a function which change string, see the following code.
void Test(char* str, char c) {
str[1] = c;
}
int main(){
Test("Hi", '2');
}
I notice it made some run time error. I know how to prevent the error.
char buff[3] = "Hi";
Test(buff,'2');
but I don't know why the first example made run time error. I guess, if I pass string directly, it becomes const char. Does anyone explain what happened exactly?
ps.
what if I use char* str = "hi", then pass it into the argument?
char* buff = "Hi";
Test(buff,'2');
like this. Can I modify buff?

Because "Hi" is string literal and it's not allowed to be modified, they are read-only (the type of string literal is const char[n]).
Modifying it is undefined behavior.
Regarding your edit: char* str = "hi" is invalid, it should be const char* str = "hi". Which is pointer to const char. Again, modifying it is disallowed.

When you don't explicitly allocate memory for strings, compiler stores them in read-only memory. So, any modification to such strings result in run time error.
Test("Hi", '2');
Here in the above case "Hi" string is stored in read-only memory.
char *buff = "Hi";
Test(buff,'2');
Here also "Hi" is stored in the read-only memory and the starting address is returned to buff character pointer, which is same as above. You can overcome such errors by allocating memory for the string and then pass that reference. Like
char buff[3] = "Hi";
Test(buff,'2');
or
char *buff = (char *)malloc(SIZE);
strcpy(buff, "Hi");
Test(buff,'2');
Please refer to this link http://www.geeksforgeeks.org/memory-layout-of-c-program/

Often string constants are in read-only memory, causing a runtime error when you attempt to modify it.
In your second example, you put the string into a buffer on the stack, so it can be updated without error.

Literal strings are not modifiable. When I compile your code with GCC I get the warning:
testptr.cpp:6: warning: deprecated conversion from string constant to 'char*'

Runtime Error:
char* buff = "Hi"; // buff points to an address in the code-section, which is a Read-Only section
buff[1] = 'x'; // Illegal memory access violation
Compilation Error:
const char* buff = "Hi"; // This is a correct declaration, which will prevent the runtime error above
buff[1] = 'x'; // The compiler will not allow this
All Good:
char buff[] = "Hi"; // buff points to an address in the stack or the data-section, which are both Read-Write sections
buff[1] = 'x'; // Works OK
Notes:
In all cases, a string "Hi" is placed in the code-section of the program.
In the last example, the contents of that string are copied into the buff array.
In the last example, the buff array is located in the stack if buff is a non-static local variable, and in the data-section of the program otherwise.

Related

Using static_cast on char* type to get the address , and getting 24 bit and 48-bit address

#include<iostream>
using std::cout;
using std::endl;
int main()
{
char name[] = "abcde";
//char *name = "abcde";
cout << name<<"\n";
//type casting to get the address of char array
cout<<static_cast<void *>(name);
return 0;
}
NO error or warning
output: abcde
0x7fff1cea50c0
But when i use * operator instead of [ ] , it still gives output but
with warning "deprecated conversion from string constant 'char*' " and
output as
abcde
0x400964
Why such different address 24 bit and 48 bit, and why the warning?
Using Codeblocks , OS:Ubuntu, 64-bit system
Warning means you assign a constant string to a writable pointer, in more details it's described, for example, here
If you aren't planning to write using this pointer it's sort of safe and the warning could be suppressed, but then again, why not make it const to avoid risk of shooting yourself in the foot?
As for the address, the difference comes from the fact that one is allocated on the stack, while other is in read-only-data section which rather far from each other
char *name = "abcde";
Assigning a string literal (aka a const char[]) to a non-const char* pointer is deprecated in C++11, thus the warning.
This declaration sets name to point at the starting address of the string literal's character data.
String literals reside in read-only memory. Code will crash if it tries to write to read-only memory using a non-const pointer. Pointers to literal data should be declared as const, eg: const char *name = "abcde";
char name[] = "abcde";
Initializing a char[] buffer (const or otherwise) with a string literal is allowed, so no warning.
This declaration allocates name at runtime to the full length of the string literal and then copies the string literal's character data into it.
This explains the difference in address outputs. One is an address in read-only memory, the other is an address in stack memory.

Can you copy data to `char*` pointer without allocating resource first?

I have seen an example here: http://www.cplusplus.com/reference/string/string/data/
...
std::string str = "Test string";
char* cstr = "Test string";
...
if ( memcmp (cstr, str.data(), str.length() ) == 0 )
std::cout << "str and cstr have the same content.\n";
Question> How can we directly copy data into the location where the pointer cstr pointed to without explicitly allocating space for it?
memcmp is comparing the content of memory pointed to by the two pointers. It does not copy anything.
[EDIT] The question was edited to add a concrete question. The answer is: you need the pointer to point to memory allocated one way or another if you want to copy data there.
How can we directly copy data into the location where the pointer cstr pointed to without explicitly allocating space for it?
You cannot, using an initialisation from a character string literal.
That memory will be placed in the static storage section of your program, and writing there is calling undefined behaviour (merely an exception in your particular compilers implementation).
lets assume that you used memcpy(cstr,x,...) instead of memcmp.
You use phrase 'without allocating resource first'. This really has no meaning.
For memcpy to work cstr must point at valid writable memory.
so the following work
char *cstr = new char[50];
char cstr[50];
char *cstr = malloc(50);
The following might work but shouldnt
char *cstr = "Foo"; // literal is not writable
This will not
char *cstsr = null_ptr;
char *cstrs; // you just might get lucky but very unlikely

pointer to char array, unhandled exception

I'm new to C++ and I'm playing with pointers. I can't figure out why this piece of code doesn't work for me. Can you tell me what's wrong with it?
char * name = "dharman";
char *ptr = name+3;
*ptr = 'a';
printf("%s", name);
I get unhandled exception all the time.
This alone is an error:
char * name = "dharman";
The string is in constant memory but the pointer's type indicates it can be modified. Attempting to modify it produces undefined behavior: on other platforms the program will work but you got unlucky.
This was a quirk in C++03; the newer C++11 spec makes it illegal. The reason it was ever done was C compatibility.
Whether you're writing in C++ or plain C, the solution is simple:
char name[] = "dharman";
Now the compiler stores the data in read-write memory because you have asked for an array of char, not a pointer to some other memory.
String literals, like "dharman", are read-only and you cannot modify them. Instead, create and initialize an array that is not read only.
char name[] = "dharman";
name is a pointer to a string literal "dharman", which is located in read-only memory.
In your statement *ptr = 'a', you are trying to modify this string literal, which results in Undefined Behavior
It doesn't work because "dharman" is constant, it's a string literal. You cannont change it!
String literals are usually placed in read-only segments of memory.
You are trying to modify a constant string.
You need to copy the constant first to some memory that you own.
Try this:
char *name = (char*) malloc(10);
memcpy(name, "dharman", strlen("dharman"));
...
You are setting name to point at a const string and then trying to modify it. Copy the string to a modifiable location:
char *name = (char*) malloc(strlen("dharman") + 1);
memcpy("dharman", name, strlen("dharman") + 1);
The reason for unhandled exception in your case is.In your code
char *ptr= name+3;
consider the base address of name as eg:23300, so char *ptr =name+3 will be equal to
23300+(3*sizeof(char)).so now ptr points to 23300+(3*1)=23303.each element occupies one bye for char so ptr will point to letter 'a' in "dharman".since "dharman" is char const you can't its value that's why you are getting error.if u remove the line *ptr=3.the code will work without out any issue.I hope you find this post useful.

char *str; str="HELLO"; How does that work without allocating any memory for the string?

Code:
#include <stdio.h>
int main() {
char *str;
char i = 'a';
str = &i;
str = "Hello";
printf("%s, %c, %x, %x", str, i, str, &i);
return 0;
}
I get this output:
Hello, a, 403064, 28ff0b
I have following two doubts:
How can I store a string without allocating any memory for it. str is a character pointer and is pointing to where char variable i. When I add str = "Hello"; aren't I using 5 bytes from that location 4 of which are not allocated?
Since, I code str = &i; shouldn't str and &i have same value when I printf them? When I remove the str = "Hello"; statement str and &i are same. And if str and &i are same then I believe when I say str = "Hello" it should overwrite 'a' with 'H' and the rest 'ello\0' come into the subsequent bytes.
I believe the whole problem is with str = "Hello" statement. It doesn't seem to be working like what I think.
Please someone explain how it works??
When the compiler encounters a string literal, in this case "Hello", memory is allocated in the static (global) memory area. This "allocation" is done before your program executes.
When your program starts executing at main, a stack frame is allocated to store the local variables of main: str and i. Note that str is a simple variable that just stores an address. It does not store any characters. It just stores a pointer.
The statement str = &i; writes into variable str the address of i.
The statement str = "Hello" writes into the variable str, the address of the string literal "Hello" which has been pre-allocated by the compiler. This is a completely different address than that of i. That assignment does not move any of the characters in the word "Hello" anywhere at all.
TL;DR the value of a "string" variable in C is just a pointer. Assigning to a string variable is assigning a number, namely an address.
The compiler writes the sequence of bytes { 'H', 'E', 'L', 'L', 'O', '\0' } in a section of the executable called the data segment.
When the application runs, it takes the address of these bytes and stores them in the variable representing 'str'.
It doesn't have to "allocate" memory in the sense that, at run time, the program does not have to ask the OS for memory to store the text.
You should try to avoid treating string literals like this as non-const. GCC's "-Wall" option promotes assignment of string literals to "char*" pointers as
warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
Many compilers, when compiling with optimization, will do something called "string pooling", which avoids duplicating strings.
const char* str1 = "hello";
const char* str2 = "hello";
If compiled with string pooling, the executable might only contain one instance of "hello".
When I say str = "Hello" aren't I using 5 bytes from that location 4
of which are not allocated?
No. The compiler sets aside 6 bytes (remember the null terminator) in a different part of memory (a read-only part, but that's an answer to a different question). The assignment:
str = "Hello";
causes str to point to the location of the first of these 6 bytes, the H.
Since, I said str=&i; shoudln't str and &i have same value when I
printf them?
Yes, but you set str to point to something else on the very next line, before you printed anything.
The literal string "Hello" is taking 6 bytes of memory somewhere, probably in the program space. Assigning the pointer to it just sets the pointer to where the string already exists. It doesn't copy the characters at all.
If you wanted to copy the characters you would need to use strcpy, but as you did not set the pointer to a writable buffer of sufficient size it would cause undefined behavior if you did.
str is a pointer to a char. When you say str = &i; you are pointing it to an int. When you say str = "Hello"; you are changing str to point to a location where the character sequence 'H', 'e', 'l', 'l', 'o', 0 is stored.
But you say str = something else right after you say str = &i
Looks like you haven't quite grasped pointers yet...
Okay, simply put, every string is a pointer in C.
If we run with this:
int main() {
char *str;
char i='a';
str = &i;
str = "Hello";
printf("%s, %c, %x, %x", str, i, str, &i);
return 0;
}
When you set str = &i, you are making str point to i. Thus, i == *str and &i == str hold true.
When you call str = "Hello";, str now points to a statically allocated array of size 6 (this usually resides directly in your program code). Because str is a pointer, when you reset it to point to the new array, it makes no change to i. Now, if instead of setting str to "Hello", we did *str = 'Z';, i would now have the value of 'Z', while str still points to i.
First how can I store the string without allocating any memory for it. str is a chracter pointer and is pointing to where char i is stored. When I say str = "Hello" aren't I using 5 bytes from that location 4 of which are not allocated?
The memory for the string is allocated by the compiler. I don't think the standard specifies exactly how the compiler must do this. If you run 'strings' against your executable, you should find "Hello" in there somewhere.
Since, I said str=&i; shoudln't str and &i have same value when I printf them? When I remove the str = "Hello" statement str and &i are same. And if str and &i are same then I believe when I say str="Hello" it should overwrite 'a' with 'H' and the rest 'ello\0' come into the subsequent bytes.
I think what you are missing here is that str = "Hello" does not copy the string to the location pointed to by str. It changes what str points to. "Hello" is in memory and you are assigning that memory location to the pointer. If you want to copy memory to a pointer, you need to use memcpy() or something similar.

Why can't I write to a string literal while I *can* write to a string object?

If i define something like below,
char *s1 = "Hello";
why I can't do something like below,
*s1 = 'w'; // gives segmentation fault ...why???
What if I do something like below,
string s1 = "hello";
Can I do something like below,
*s1 = 'w';
Because "Hello" creates a const char[]. This decays to a const char* not a char*. In C++ string literals are read-only. You've created a pointer to such a literal and are trying to write to it.
But when you do
string s1 = "hello";
You copy the const char* "hello" into s1. The difference being in the first example s1 points to read-only "hello" and in the second example read-only "hello" is copied into non-const s1, allowing you to access the elements in the copied string to do what you wish with them.
If you want to do the same with a char* you need to allocate space for char data and copy hello into it
char hello[] = "hello"; // creates a char array big enough to hold "hello"
hello[0] = 'w'; // writes to the 0th char in the array
string literals are usually allocated in read-only data segment.
Because Hello resides in read only memory. Your signature should actually be
const char* s1 = "Hello";
If you want a mutable buffer then declare s1 as a char[]. std::string overloads operator [], so you can index into it, i.e., s1[index] = 'w'.
Time to confuse matters:
char s0[] = "Hello";
s0[0] = 'w';
This is perfectly valid! Of course, this doesn't answer the original question so here we go: string literals are created in read-only memory. That is, their type is char const[n] where n is the size of the string (including the terminating null character, i.e. n == 6 for the string literal "Hello". But why, oh, why can this type be used to initialize a char const*? The answer is simply backward compatibility, respectively compatibility to [old] C code: by the time const made it into the language, lots of places already initialized char* with string literals. Any decent compiler should warn about this abuse, however.