Why is my char* writable and sometimes read only in C++ - c++

I have had really big problems understand the char* lately.
Let's say I made a recursive function to revert a char* but depending on how I initialize it I get some access violations, and in my C++ primer I didn't find anything giving me the right path to understand so I am seeking your help.
CASE 1
First case where I got access violation when trying to swap letters around:
char * bob = "hello";
CASE 2 Then I tried this to get it work
char * bob = new char[5];
bob[0] = 'h';
bob[1] = 'e';
bob[2] = 'l';
bob[3] = 'l';
bob[4] = 'o';
CASE 3 But then when I did a cout I got some random crap at the end so I changed it for
char * bob = new char[6];
bob[0] = 'h';
bob[1] = 'e';
bob[2] = 'l';
bob[3] = 'l';
bob[4] = 'o';
bob[5] = '\0';
CASE 4 That worked so I told myself why wouldn't this work then
char * bob = new char[6];
bob = "hello\0";
CASE 5 and it failed, I have also read somewhere that you could do something like
char* bob[];
Then add something to that.
My question is why do some fail and other not, and what is the best way to do it?

The key is that some of these pointers are pointing at allocated memory (which is read/write) and some of them are pointing at string constants. String constants are stored in a different location than the allocated memory, and can't be changed. Well most of the time. Often vulnerabilities in systems are the result of code or constants being changed, but that is another story.
In any case, the key is the use of the new keyword, this is allocating space in read/write memory and thus you can change that memory.
This statement is wrong
char * bob = new char[6];
bob = "hello\0";
because you are changing the pointer not copying the data. What you want is this:
char * bob = new char[6];
strcpy(bob,"hello");
or
strncpy(bob,"hello",6);
You don't need the nul here because a string constant "hello" will have the null placed by the compiler.

char * bob = "hello";
This actually translated to:
const char __hello[] = "hello";
char * bob = (char*) __hello;
You can't change it, because if you'd written:
char * bob = "hello";
char * sam = "hello";
It could be translated to:
const char __hello[] = "hello";
char * bob = (char*) __hello;
char * sam = (char*) __hello;
now, when you write:
char * bob = new char[6];
bob = "hello\0";
First you assign one value to bob, then you assign a new value to it. What you really want to do here is:
char * bob = new char[6];
strcpy(bob, "hello");

You should always use char const* for pointers to string literals (stuff in double quotes). Even though the standard allows char* as well, it does not allow writing to the string literal. GCC gives a compile warning for assigning a literal address into char*, but apparently some other compilers don't.

Edit: The question was retagged as C++ instead of C which was originally there but re-tagged....
Ok. You have got a couple of things mixed up...
new is used by C++, not C.
Case #1. That is declaring a pointer to char. You should be able to manipulate the string...can you show the code in what you did to do swapping characters.
Case #2/#3. That you got random crap, and discovered that a nul terminator i.e. '\0'...occupies every single string you'll encounter for the duration of C/C++, possibly for the rest of your life...
+-+-+-+-+-+--+
|H|e|l|l|o|\0|
+-+-+-+-+-+--+
^
|
Nul Terminator
Case #4 did not work as you need to use a strcpy to do that job, you cannot simply assign a string like that after calling new, when you declare a string char *s = "foo"; that is initialized at compile time. But when you do it this way, char *s = new char[6]; strcpy(s, "hello"); that gets copied into the pointer variable s.
You will eventually discover that this pointer to a memory block occupied by s will easily get over-written which will induce a fit of conniptions as you realize that you have to be careful to prevent buffer overflows...Remember Case #3 in relation to nul terminator...don't forget that, really, that string's length is 6, not 5 as we're taking into account of the nul terminator.
Case #5. That is declaring a pointer to array of type char, i.e. a multi-dimensional array, think of it like this
*(bob + 0) = "foo";
*(bob + 1) = "bar";
I know there is a lot to digest...but feel free to post any further thoughts... :) And best of luck in learning...

Related

Is there any way to change char* value at any index?

As I know, if we declare char* in our program then it gives memory from read-only area, so we are not able to change a char at any position in the array.
char *ch = "sitaram";
ch[2] = 'y';
The above code will not run properly, as we are changing read-only memory.
One approach is we can declare our char array as
char ch[] = "sitaram";
and then we can change a value at an index.
Is there any way where I can change a char value at any index in a char*?
Use the modern C++ approach for mutable string values
std::string str{"sitaram"};
str[2] = 'y';
String literals (i.e. values enclosed in "") are by default of type const char[n] (where n is the length of the string literal +1 for the null character) in C++ and because of that they are immutable, any attempt to modify them results in undefined behavior.
When you say:
char *ch = "sitaram";
The compiler does the following:
it allocates the string "sitaram" at program start (static storage duration). This string can be put into read-only memory.
when your program arrives at this line, it allocates the pointer ch, and makes this pointer to point to the statically allocated "sitaram" string.
if you do ch[2] = 'y', then you're trying to modify the 3rd character of the statically allocated string. Usually, you get a crash (because it is in read-only memory)
On the other hand, if you do the following:
char ch[] = "sitaram";
When the program hit this line, it allocates memory for the array ch[] (for 8 chars), then copies the string "sitaram" into this memory. If you do ch[2] = 'y', then you modify this allocated memory, which is perfectly fine to do.
If you want to modify a string with char *, it should point to a memory which is modifiable. For example:
char ch[] = "sitaram";
char *xx = ch;
xx[2] = 'y'; // it is the same as ch[2] = 'y';
Using char arrays:
char text[] = "sitaram";
text[3] = 'o';
char * p = &text[0];
p[4] = 'x';
cout << text;

Is it valid to append a string to a character array like char p [] = "TEST" using strcat

#include<iostream>
#include<string.h>
using namespace std;
int main()
{
char p [] = "TEST";
strcat (p, "VAL");
cout << p;
return 0;
}
If what I understand is correct, a statement like char p [] = "TEST"; will allocate space from stack. When I call strcat() for such a string how the storage for p[] is adjusted to accommodate extra characters?
Last cout prints "TESTVAL". Is it valid to call strcat like this? If yes, how this works? I might be having problem with my understanding, but feeling like I lost touch. So this could easily be a dumb question. Please shed some light.
The storage is not adjusted, the call is not valid, and the behaviour of the code is undefined.
when you write
char buffer[] = "some literal";
it is expanded to
char buffer[sizeof("some literal")] = "some literal";
which has exact size to store "some literal" and nothing more.
when you concate another string in the end of the current buffer- you write beyond the boundries of the array - having undefined behavior.
another issue that in C++, we usually use std::string to handle strings, which does all the memory adjustment for us automatically.
p reserves space for 5 characters (4 + 1 for the null terminator). You are then appending 3 more characters which needs room for 8 (7 + 1 for the null). You don't have enough room for that and will be overwriting the stack. Depending on your compiler and build settings, you may not see any difference as potentially, the compiler leaves spaces between stack variables. On an optimised release build, you will probably get a crash.
If you change your code to look like this, you should see that sentinel1 & 2 are no longer 0 (it depends on the compiler which one will get trashed).
#include<iostream>
#include<string.h>
using namespace std;
int main()
{
int sentinel1 = 0;
char p [] = "TEST";
int sentinel2 = 0;
strcat (p, "VAL");
cout << p << sentinel1 << sentinel2;
return 0;
}

Ustring error (during printing)

I want to parse UTF-8 file to ustring, I read this file in str.
There is an error:
terminate called after throwing an instance of 'Glib::ConvertError'.
What should I do?
char* cs = (char*) malloc(sizeof(char) * str.length());
strcpy(cs, str.c_str());
ustring res;
while (strlen(cs) > 0) {
gunichar ch = g_utf8_get_char(cs);
res.push_back(ch);
cs = g_utf8_next_char(cs);
}
wofstream wout("output");
cout << res << endl;
This looks very wrong:
char* cs = (char*) malloc(sizeof(str.c_str()));
as sizeof(str.c_str()) is bound to give you some small number like 4 or 8 (whichever is the size of a pointer on your machine, as the result of str.c_str().
Of course, it doesn't REALLY matter, since the next line, you are leaking the memory you just allocated incorrectly:
cs = const_cast<char*> (str.c_str());
I'm far from convinced that you need the const_cast<char *> (it is certainly WRONG to do this, since modifying the string inside a string is undefined behaviour).

Simple C++ char array encryption function - Segment fault

As always, problems with the pointers. I am trying to create a very simple "encryption/decryption" function for char arrays. Yes, I know I can use strings, but I want to improve my knowledge about pointers and make use of simple bytes to achieve a simple task.
So, I created a simple struct like this:
struct text {
char* value;
int size;
}
And I created this simple function:
text encrypt(text decrypted) {
char key = 'X';
for (int i=0; i<decrypted.size; i++) {
decrypted.value[i] = decrypted.value[i] ^ (key + i) % 255);
}
return decrypted;
}
At this point, an experienced C++ programmer should have spot the problem, I think. Anyway, I call this function like this:
...
text mytext;
mytext.value = new char[5];
mytext.value = "Hello";
mytext.size = 5;
mytext = encrypt(mytext);
...
I get, like always, a 'Segmentation fault(core dumped)' error. This is Linux, and, of course, g++. What have I done, again? Thanks!
mytext.value = new char[5];
mytext.value = "Hello";
on the second line, you throw away the (handle to the) allocated memory, leaking it, and let mytext.value point to a string literal. Modifying a string literal is undefined behaviour, and usually crashes, since string literals are often stored in a read-only memory segment.
If you insist on using a char*, you should strncpy the string into the allocated memory (but be aware that it won't be 0-terminated then, you should better allocate a new char[6] and copy also the 0-terminator).
Or let decrypt create a new text that it returns:
text encrypt(text decrypted) {
char key = 'X';
text encrypted;
encrypted.size = decrypted.size;
encrypted.value = new char[encrypted.size];
for (int i=0; i<decrypted.size; i++) {
encrypted.value[i] = decrypted.value[i] ^ (key + i) % 255;
}
// What about 0-terminators?
return encrypted;
}
But, as you're using C++, std::string would be a better choice here.
You're modifying string literals:
mytext.value = "Hello";
after this, you can no longer legally mutate what mytext.value points to, you can only re-assign the pointer.
The fix: use std::string

How to convert a char* to a string?

When I convert char* to an string it gives an bad memory allocation error in 'new.cpp' . I used following method to convert char* called 'strData' and 'strOrg' to string.
const char* strData = dt.data();
int length2 = dt.length();
string s1(strData);
First time it work without any problem. But in the second convertion it gives above error. When I swap the two conversion in the order, it give the error always in the second conversion regardless of the char* I am converting. Whole code is shown in the following.
mysqlpp::Query query = conn.query("SELECT data,origin from image where id =2");
mysqlpp::UseQueryResult res = query.use();
mysqlpp::Row eee= res.fetch_row();
mysqlpp::Row::reference dt = eee.at(0);
mysqlpp::Row::reference org = eee.at(1);
const char* strData = dt.data();
int length2 = dt.length();
string s1(strData);
istringstream is1(s1);
char * imgData = new char;
is1.read(reinterpret_cast<char *> (imgData), length2);
delete [] strData;
const char* strOrg = org.data();
int length3 = org.length();
string s2(strOrg);
istringstream is2(s2);
char * imgOrg = new char;
is2.read(reinterpret_cast<char *> (imgOrg), length3);
delete [] strOrg;
This where the error comes from
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
void *p;
while ((p = malloc(size)) == 0)
if (_callnewh(size) == 0)
{ // report no memory
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return (p);
}
How can I solve this?
Instead of
char * imgData = new char;
is1.read(reinterpret_cast<char *> (imgData), length2);
try
char * imgData = new char[length2];
is1.read(reinterpret_cast<char *> (imgData), length2);
When you read data from an istringstream using read, the buffer you provide must have enough space to hold the results!
If you call new char; you get space for one char. Use new char[n]; to get space for n.
delete [] strData;
This is bad. The line above it probably is also but I know this one is.
You're deleting dt.data(). If I recall correctly this is guaranteed to be the internal buffer of the string.
This may or may not be your underlying problem, like I said, I suspect the line above it is bad also since you pass in a pointer to a single character to what would seem to expect a buffer of some length.
I believe the problem (or at least part of the problem) lies with your allocation:
char * imgData = new char;
This only allocates 1 char, and then istream.read will assume that imgData is a buffer of chars (notice plural) and place whatever it reads into the single char you allocated, and then beyond that into the memory used by who knows what.
The result is typically called "undefined behaviour" - sometimes you'll get away with it as in the first instance, other times you won't, as in the second conversion.