I'm learning const and pointers playing with examples. From this thread I read that:
const char* the_string : I can change the char to which the_string points, but I cannot modify the char at which it points.
int main()
{
const char* a = "test";
char* b = "other";
a = b;
cout << a << endl; //prints "other"
}
Why can I modify at which char a points ?
You can set a to point at something else since a is itself not const: only the data to which it points is const.
Setting b = a would not be allowed, since you'd be casting away const.
If you want to prevent a = b then write
const char* const a = "test";
Related
The last 2 cout statements have the same size. why?
int main()
{
char ch=127;
cout<<sizeof(ch)<<endl; //Size=1
cout<<sizeof("Hello")<<endl; //Size=6
cout<<sizeof("Hello"+ch)<<endl; //Size=8
cout<<sizeof("HelloWorld"+ch)<<endl; //Size=8
return 0;
}
Please explain.
Thanks
When you do "Hello"+ch the array containing the string "Hello" decays to a pointer to its first element, and you add ch to this pointer.
The result of pointer arithmetic is a pointer, which is what you get the size of.
Equivalent code would be something like
char const hello[] = "Hello";
char const* phello = hello; // equivalent to &hello[0]
char const* result = phello + ch;
cout << sizeof(result) << endl;
Fairly new to C++ here. I am trying to figure out if I can optimize my code by not calling the same function multiple times. For example see below:
funcCall is a standalone function so it cannot be removed, all it needs to know is those three paramters..
const char *a = "H";
const char *b = "e";
const char *c = "l";
const char *d = "l";
const char *e = "o";
const char *f = "Hi";
funcCall(f,a,b);
funcCall(f,c,d);
funcCall(f,d,e);
void funcCall(const char *one, const char *two, const char *three)
{
//Kindly ignore the syntax
//open the file and write the first two parameters to it
fopen(three.txt);
fwrite(one,two,three.txt); //ignore syntax
fclose(three.txt);
}
You can make an array of the characters, and loop over it two at a time, like so:
char abcdef[] = "Helllo";
const char* hi = "Hi";
for (char* p = abcdef; p < abcdef + 6; p += 2) {
funcCall(hi, p[0], p[1]);
}
This differs from your example in that it passes characters as the second and third arguments to funcCall, rather than null-terminated character strings.
After your edit, it looks like the parameters are really supposed to be strings, not just characters, so you'd want to have an array of strings rather than an array of characters. So you can do something like
std::vector<const char*> args = {"One", "Two", "Three"};
std::vector<const char*> files = {"A.txt", "B.txt", "C.dat"};
const char* hi = "Hi";
for (int i = 0; i < std::min(args.size(), files.size()); ++i) {
funcCall(hi, args[i], files[i]);
}
where funcCall takes const char* arguments as in your example. (It would probably be better to use std::string.)
I hope I have clearly stated my goal in the topic and following is the code I am using.
#include <stdio.h>
#include <inttypes.h>
#include <iostream>
using namespace std;
int main() {
const char *data_ptr =(char*)"test";
const uint8_t* p = reinterpret_cast<const uint8_t*>(&data_ptr);
uint8_t* p1= const_cast<uint8_t*>(p);
char* p2 = reinterpret_cast<char*>(p1);
const char *final= const_cast<const char*>(p2);
string s1( data_ptr);
string s( reinterpret_cast<char const*>(p1),4) ;
cout<<"data_ptr is "<<data_ptr<<endl;
cout<<"p "<<p<<endl;
cout<<"p1 "<<p1<<endl;
cout<<"p2 "<<p2<<endl;
cout<<"final is "<<final<<endl;
cout<<"final1 is "<<s1.size() << "<-->"<<s.size()<<endl;
return 0;
}
and what it prints is as follows.
data_ptr is test
p X#
p1 X#
p2 X#
final is X#
final1 is 4<-->4
What should I do to get the "test" as a string.
As pointed out in the comments above, your data_ptr cast in line
const uint8_t* p = reinterpret_cast<const uint8_t*>(&data_ptr);
casts from a pointer to chars (char*) to a pointer of pointer of chars (in your case uint8_t*, referencing &data_ptr, which is in turn char*). That's also why your string s1 in
string s1( data_ptr);
Contains the correct test string, while s, as initialized in
string s( reinterpret_cast<char const*>(p1),4) ;
with p1 referencing the wrong pointer to pointer to chars from
const uint8_t* p = reinterpret_cast<const uint8_t*>(&data_ptr);
uint8_t* p1= const_cast<uint8_t*>(p);
is just initialized with garbage data.
So just change your line
const uint8_t* p = reinterpret_cast<const uint8_t*>(&data_ptr);
to
const uint8_t* p = reinterpret_cast<const uint8_t*>(data_ptr);
and both, s and s1 contain your source string "test".
"test" will not fit in an unsigned char. You should use the standard c functions atoi and itoa to do the conversion. You can also use these functions if you want to do it character by character.
I am not entirely sure what you are trying to do here. However, changing
const uint8_t* p = reinterpret_cast<const uint8_t*>(&data_ptr);
to
const uint8_t* p = reinterpret_cast<const uint8_t*>(data_ptr);
would do the job for you.
std::string has a constructor taking a char* or const char* as a parameter. It also has a function c_str() to do the conversion back to a char* so all thats needed is this:
const char* charptr = "Test";
string str(charptr);
const char* charptr2 = str.c_str();
//just to verify:
cout << charptr << "\n";
cout << str << "\n";
cout << charptr2 << "\n";
Edit: As you stated in the comments you need an uint8_t, for this just take the raw char* as it is:
const uint8_t* intptr = reinterpret_cast<const uint8_t*>(charptr);
Try it online: http://ideone.com/drJYuR
I have next problem. I used int memcmp ( const void * ptr1, const void * ptr2, size_t num );
function to compare two void pointers which contain integers. This worked for me very well.
int firstValue = 5;
int secondValue = 3;
void* firstValueVoid;
void* secondValueVoid
firstValueVoid = new int(firstValue);
secondValueVoid = new int(secondValue);
int compare = memcmp(firstValueVoid, secondValueVoid, 4);
cout << compare << endl;
But, if I am trying to to the same for strings, it always shows that first value is less than second one.
string firstValue = "abc";
string secondValue = "a";
int testSize = firstValue.length();
void* firstValueVoid;
void* secondValueVoid
firstValueVoid = new string(firstValue);
secondValueVoid = new string(secondValue);
int compare = memcmp(firstValueVoid, secondValueVoid, testSize);
cout << compare << endl;
So compare value always becomes equal to -1. Even if I am making firstValue = "a"; secondValue = "a";.
Please help someone. I already tried everything I had in my mind to fix this problem.
Thank you in advance!
From cppreference:
int memcmp( const void* lhs, const void* rhs, std::size_t count );
Reinterprets the objects pointed to by lhs and rhs as arrays of unsigned char and compares the first count characters of these arrays. The comparison is done lexicographically.
In your case, you're comparing two std::string objects whose byte sequences differs from the buffer that holds the actual string. You're getting this error because these objects are not naked char arrays but rather actual classes.
Here is the note from the actual page (emphasis mine):
This function reads object representations, not the object values, and is typically meaningful for trivially-copyable objects only. For example, memcmp() between two objects of type std::string or std::vector will not compare their contents.
You should be using an array of char for this:
char abc[] = "abc";
char abd[] = "abd";
int bytes = std::min(sizeof abc, sizeof abd);
int c1 = memcmp(abc, abd, bytes);
int c2 = memcmp(abd, abc, bytes);
If you really need void*s:
void* a = abc;
void* b = abd;
int c1 = memcmp(reinterpret_cast<char*>(a),
reinterpret_cast<char*>(b), bytes);
int c2 = memcmp(reinterpret_cast<char*>(b),
reinterpret_cast<char*>(a), bytes);
Just declare the pointers as char* or char[] (which essentially is the same in this case), and compare them like that. This works fine:
char firstValue[] = "abc";
char secondValue[] = "a";
int testSize = string(firstValue).size();
int compare = memcmp(firstValue, secondValue, testSize);
There's a working example at the C++ reference page too.
If you REALLY need the void pointers use them like this:
int someData1 = 35243242;
int someData2 = 34243251;
void *ptr1, *ptr2;
ptr1 = &someData1;
ptr2 = &someData2;
int testSize = sizeof(int);
int compare = memcmp((char*)ptr1, (char*)ptr2, testSize);
cout << compare << endl;
or with strings:
string someData1 = "sdadsasd";
string someData2 = "sdadsasd";
void *ptr1, *ptr2;
const char *c1, *c2;
c1 = someData1.c_str();
c2 = someData2.c_str();
ptr1 = (char*)c1;
ptr2 = (char*)c2;
int testSize = someData1.size();
int compare = memcmp(ptr1, ptr1, testSize);
A little context: I'm trying to make a very simple hashing function/hash table as described here. I'm basically on the first step, blindly adding a key to an array based on the letter it starts with (no checking if space is occupied yet). The code I'm using to do this so far:
int main(int argc, char **argv) {
char *arrayKeys[300];
std::string aName("Charles");
char *aNameCpy = new char[aName.size() + 1];
std::copy(aName.begin(), aName.end(), aNameCpy);
aNameCpy[aName.size()] = '\0';
int kPos = storeKey(arrayKeys, aNameCpy);
std::cout << "The new position in arrayKeys for 'Charles' is: " <<
kPos << "\ncontaining the text: " << arrayKeys[kPos] << std::endl;
delete[] aNameCpy;
return 0;
}
int storeKey(char **keys, char *key) {
int charLett = -1;
charLett = (int)key[0];
if(charLett != -1)
charLett = charLett - 65;
keys[charLett * 10] = key;
return charLett*10;
}
My question is, how can I add a string to the array (arrayKeys) where it is fully apart of the array, and not reliant upon the original string? If I delete the copy of the string (aNamCpy) before I print the array key out, the array key turns into garbled symbols. I'm copying the string before sending it to the function because I need a non-const string to add to the arrayKeys array (so it can be modified), and any method of string I looked at seemed to return const.
(Another version of this I attempted can be found here, but I would rather not initialize the arrayKeys like that - with a definite second dimension (string) length)
C++ is still very new to me so I can't figure out how to juggle the non-const part with copying the string into arrayKeys. Any help would be very much appreciated.
Here's how I'd change the code to use more modern C++ constructs. I think you'll find this way easier to use.
int storeKey(vector<string> &keys, const string &key) {
int charLett = -1;
if (!key.empty()) { // you weren't doing this before!
charLett = key[0];
charLett = toupper(charLett) - 'A';
keys[charLett * 10] = key;
}
return charLett*10;
}
int main() {
vector<string> arrayKeys(300);
std::string aName("Charles");
// No need to bother with the awkward copying.
// std::vector and std::string will take care of it for us.
int kPos = storeKey(arrayKeys, aName);
if (kPos >= 0) {
cout << "The new position in arrayKeys for 'Charles' is: " <<
kPos << "\ncontaining the text: " << arrayKeys[kPos] << endl;
}
// Don't have to remember to delete anything because nothing was new'ed.
return 0;
}
(#Kristo has the right idea. I'm just going to add a comment to the question as asked.)
Basically, don't delete aNameCpy. You require the copy to remind valid and therefore it shouldn't be deleted. You should only delete the strings if and when you ever delete the entire hash.
C++ is still very new to me so I can't figure out how to juggle the
non-const part
You could declare both keys and key to be const char **keys, const char *key. keys is pointer-to-pointer-to-char. More precisely, it's a pointer to nonconst pointer to const char. In other words, you can modify keys, you just cannot modify the actual characters it points (indirectly) at.
So, simply put const in your declaration of storeKey int storeKey(const char **keys, const char *key) and update arrayKeys accordingly const char *arrayKeys[300];
One final style issue: You should copy the string inside storeKey, not in main. This is better design, as it makes clear to the reader that storeKey "owns" the copy.
int storeKey(char **keys, const char *key) {
char * the_copy = new char[strlen(key)+1];
strcpy(the_copy, key);
... and so on
But, in short, use C++ string instead of all this, if you can!