When we declare the const variable it is said in Bruce eckel book that constant folding happens that means memory is not allocated for the variable.
What happens when we declare the variable as const?
How is the compiler free to optimise const variables?
Is memory for const variables is always allocated, and under which circumstances it may not be?
The compiler is free to optimise const variables (and anything else) as long as you can't tell the difference from what the program does.
For example:
const int three = 3;
const int four = 4;
int f() { return three * four; }
Here the compiler is free to omit allocating storage for the variables, and will probably produce exactly the same code as if it was written return 12;
But if you took the address of three, or bound a reference to it, or declared it as extern, then the compiler would probably be forced to allocate memory for it.
I found the following quote on a PDF attributed to Bruce Eckel:
const int bufsize = 100; You can use
bufsize anyplace where the compiler
must know the value at compile time.
The compiler can use bufsize to
perform constant folding, which means
the compiler will reduce a complicated
constant expression to a simple one by
performing the necessary calculations
at compile time. This is especially
important in array definitions:
Assuming that you meant "constant folding" and not "memory folding", what he means is the following:
const int i = 10;
const int j = 20;
int k = i + j;
Memory does not have to be allocated for i and j if the compiler can prove that this is the only time they are used. In that case, it can replace all three lines with int k = 30; Because the variables were marked const, the compiler is free to assume their values never change, and it is smart enough to do the addition for you in advance rather than wait for run-time.
For what its worth, I would not worry about this too much if you're still learning the language. Its an implementation detail; you can generally count on it happening, but the end result is the same either way. Write code that makes sense, use const as needed to prevent mistakes [not as a means to save memory], and if the compiler is able to spit out something special for you then all the better.
----------- Original answer follows, since it is a sort of related topic
Without a direct quote, my guess is he is referring to something like this:
//in file 1:
const char* string1 = "Hello world!";
//in file 2:
const char* string2 = "Hello world!";
//in file 3:
const char* string3 = "world!";
Under some circumstances, the compiler/linker is able to spot that string1 and string2 both point to the same string. So it does not have to create two separate string objects that contain the same data, and assert(string1 == string2) would end up succeeding. An even more intelligent setup could notice that string3 is a substring of the first two, and you end up with assert(string3 == string1+6). In the executable's actual data, you end up with one string, even though in the code there are three of them.
In C++, it doesn't really matter that they are const, because you can't assign a non-const char* to a string literal. But in general, that substitution would not be valid if any of the three strings were allowed to modify the memory they point to. The user probably doesn't intend for *string1 = '5' to change *string2, so the three strings can not be condensed in that case.
" means memory is not allocated for the variable .. "
You are mistaken. If it is a variable( be it either const or non const), it should reside in some part of memory.
When you declare a variable as const means, the variable cannot be modified in it's life time.
const int num = 10 ;
num = 20 ; // Error : num cannot be modified. It is just a read only variable.
int var = 10 ;
var = 20 ; // var is a modifiable integer variable.
Related
If I initialize several string(character array) variables in the following ways:
const char* myString1 = "string content 1";
const char* myString2 = "string content 2";
Since const char* is simply a pointer a specific char object, it does not contain any size or range information of the character array it is pointing to.
So, is it possible for two string literals to overlap each other? (The newly allocated overlap the old one)
By overlap, I mean the following behaviour;
// Continue from the code block above
std::cout << myString1 << std::endl;
std::cout << myString2 << std::endl;
It outputs
string costring content 2
string content 2
So the start of myString2 is somewhere in the middle of myString1. Because const char* does not "protect"("possess") a range of memory locations but only that one it points to, I do not see how C++ can prevent other string literals from "landing" on the memory locations of the older ones.
How does C++/compiler avoid such problem?
If I change const char* to const char[], is it still the same?
Yes, string literals are allowed to overlap in general. From lex.string#9
... Whether all string-literals are distinct (that is, are stored in nonoverlapping objects) and whether successive evaluations of a string-literal yield the same or a different object is unspecified.
So it's up to the compiler to make a decision as to whether any string literals overlap in memory. You can write a program to check whether the string literals overlap, but since it's unspecified whether this happens, you may get different results every time you run the program.
A string is required to end with a null character having a value of 0, and can't have such a character in the middle. So the only case where this is even possible is when two strings are equal from the start of one to the end of both. That is not the case in the example you gave, so those two particular strings would never overlap.
Edit: sorry, I didn't mean to mislead anybody. It's actually easy to put a null character in the middle of a string with \0. But most string handling functions, particularly those in the standard library, will treat that as the end of a string - so your strings will get truncated. Not very practical. Because of that the compiler won't try to construct such a string unless you explicitly ask it to.
The compiler knows the size of each string, because it can "see" it in your code.
Additionally, they are not allocated the same way, that you would allocate them at run-time. Instead, if the strings are constant and defined globally, they are most likely located in the .text section of the object file, not on the heap.
And since the compiler knows the size of a constant string at compile-time, it can simply put its value in the free space of the .text section. The specifics depend on the compiler you use, but be assured the people who wrote are smart enough to avoid this issue.
If you define these strings inside some function instead, the compiler can choose between the first option and allocating space on the stack.
As for the const char[], most compilers will treat it the same way as const char*.
Two string literals will not likely overlap unless they are the same. In that case though the pointers will be pointing to the same thing. (This isn't guaranteed by the standard though, but I believe any modern compiler should make this happen.)
const char *a = "Hello there."
const char *b = "Hello there."
cout << (a == b);
// prints "1" which means they point to the same thing
The const char * can share a string though.
const char *a = "Hello there.";
const char *b = a + 6;
cout << a;
// prints "Hello there."
cout << b;
// prints "there."
I think to answer your second question an explanation of c-style strings is useful.
A const char * is just a pointer to a string of characters. The const means that the characters themselves are immutable. (They are stored as part of the executable itself and you wouldn't want your program to change itself like this. You can use the strings command on unix to see all the strings in an executable easily i.e. strings a.out. You will see many more strings than what you coded as many exist as part of the standard library other required things for an executable.)
So how does it know to just print the string and then stop at the end? Well a c-style string is required to end with a null byte (\0). The complier implicitly puts it there when you declare a string. So "string content 1" is actually "string content 1\0".
const char *a = "Hello\0 there.";
cout << a;
// prints "Hello"
For the most part const char *a and const char a[] are the same.
// These are valid and equivalent
const char *a = "Hello";
const char b[] = "there."
// This is valid
const char *c = b + 3; // *c = "re."
// This, however, is not valid
const char d[] = b + 3;
Im trying to create an array with the string::size member but its complaining at the declaration of "char message[msgSize]" that the expression did not evalute to a constant.
However it alows me to declare "msgSize".
How can this be? Why am i allowed to make a constant but i'm not allowed to use it to something that needs a const.
If the answer is that: "the size of the string could change" then the same argument can be made for using sizeof(), but that works.
const unsigned int msgSize =
saveAs.size() +
sizeof("NOTE| sent get request to: ") + 10;
char message[msgSize];
memset(message, 0, msgSize);
sprintf_s(message, msgSize,"NOTE| sent get request to: %s", saveAs.c_str());
_cRec->output(message);
Well const just means that you promise that the value won't change. And you can even override that with a const_cast.
What compiler needs there is a value that can be evaluated at the compile time. This is a stronger requirement. Such values are marked with constexpr keyword.
Unfortunately you are out of luck with std::string... size() is not a constexpr.
I played with the following example:
#include <iostream>
#include <string>
using namespace std;
const string msg("Some msg");
constexpr int msg_len = msg.size();
int main() {
char msg[msg_len];
cout << sizeof(msg);
return 0;
}
The thing is that size() is not a constexpr, and you cannot make string a constexpr because it has a non-trivial destructor.
Why it is designed this way is beyond me. Seems like a counter intuitive and serious limitation. However, there are pretty clever implementation of string, for example with small storage optimization. It might be hard to make them constexpr with out serious changes in the implementation.
You would have to make your array dynamic.
The size of the string is not known at compile time, but only at run time.
Also, your listing is not a minimal compilable example. I can only assume saveAs is an std::string.
The following would work:
int main()
{
std::string myString("My string");
char * myCStyleString = new char[myString.size()];
delete[] myCStyleString;
}
because we are dynamically allocating an array there.
What are you trying to do? It looks like you just want to copy a filename into a message string. Just keep using std::string;
int main()
{
std::string myString("My string");
std::string message = "I like beans and rice with: ";
message += myString;
return 0;
}
but again, I'd need a minimal compilable example to determine your goal.
In C++ you cannot declare VLAs.
When you declare an array, for example:
char message[x];
The expression x must to be valuable at compile time, that is its value has to be well-known when the source is compiled.
In you example:
char message[msgSize];
The expression (variable) msgSize is not known at compile time, but only at run time. That because the compiler has to know how many bytes reserve in the stack.
Note: the variable msgSize is a constant value. A constant value is not an expression evaluate at compile time. It simply means that its value cannot change once has been assigned.
In C++11 has been introduced the keywork constexpr in order to define an expression which should be evaluate at compile time.
However in your case there is not way to get the size of a dynamic string at compile time. So what you have to do is use dynamic array (dynamic memory).
char* message = new char[msgSize];
// now you have an array of msgSize lenght
// ... do stuff...
// do not forget to release the memory when end
delete[] message;
Finally, I suggest you to re-elaborate your code because it's likely you don't need a dynamic array of chars, but just a std::string. Indeed you can use overloaded operator + in order to concatenate strings and the method std::string::c_str() to access as const char* for backward compatibility.
Why am i allowed to make a constant but i'm not allowed to use it to
something that needs a const.
This is because the "constant" expression you have is made up of non constant parts i.e. the size method of the string class. It is not truly constant in terms of having a known value at compile time.
Consider using constexpr variable/function in the future
If the answer is that: "the size of the string could change" then the
same argument can be made for using sizeof(), but that works.
No that same argument cannot be used for sizeof because sizeof does not need it's arguement to be a constant.
If you know for a fact that saveAs contains a string with a known size, then perhaps it would be best if you declare that size as a constant and then refer to it in your calculation:
constexpr unsigned int msgSize =
SAVEAS_SIZE +
sizeof("NOTE| sent get request to: ") + 10;
Then this will allow you to do:
char message[msgSize];
You need a compile-time constant with char message[msgSize]; because this is a local variable which uses static memory that is allocated in the data segment, so the compiler needs to calculate the number of bytes required by the code, including the local variables and arrays.
You can use dynamic memory to solve your problem. The dynamic memory is allocated in the heap. In C, you should use malloc(). In C++, you should use new[] (or better, std::vector, or even std::string). Then you can specify the memory size using a runtime value in a variable.
So, your code would look more like the follow:
char* message = new char[msgSize]; //Allocated memory
//Do everything that you need...
delete[] message; //Release memory
Or:
#include <vector>
std::vector<char> message(msgSize); //Allocated memory
//Do everything that you need...
I am trying to make a function like strcpy in C++. I cannot use built-in string.h functions because of restriction by our instructor. I have made the following function:
int strlen (char* string)
{
int len = 0;
while (string [len] != (char)0) len ++;
return len;
}
char* strcpy (char* *string1, char* string2)
{
for (int i = 0; i<strlen (string2); i++) *string1[i] = string2[i];
return *string1;
}
main()
{
char* i = "Farid";
strcpy (&i, "ABC ");
cout<<i;
}
But I am unable to set *string1 [i] value. When I try to do so an error appears on screen 'Program has encountered a problem and need to close'.
What should I do to resolve this problem?
Your strcpy function is wrong. When you write *string1[i] you are actually modifying the first character of the i-th element of an imaginary array of strings. That memory location does not exist and your program segfaults.
Do this instead:
char* strcpy (char* string1, char* string2)
{
for (int i = 0; i<strlen (string2); i++) string1[i] = string2[i];
return string1;
}
If you pass a char* the characters are already modifiable. Note It is responsibility of the caller to allocate the memory to hold the copy. And the declaration:
char* i = "Farid";
is not a valid allocation, because the i pointer will likely point to read-only memory. Do instead:
char i[100] = "Farid";
Now i holds 100 chars of local memory, plenty of room for your copy:
strcpy(i, "ABC ");
If you wanted this function to allocate memory, then you should create another one, say strdup():
char* strdup (char* string)
{
size_t len = strlen(string);
char *n = malloc(len);
if (!n)
return 0;
strcpy(n, string);
return n;
}
Now, with this function the caller has the responsibility to free the memory:
char *i = strdup("ABC ");
//use i
free(i);
Because this error in the declaration of strcpy: "char* *string1"
I don't think you meant string1 to be a pointer to a pointer to char.
Removing one of the * should word
The code has several issues:
You can't assign a string literal to char* because the string literal has type char const[N] (for a suitable value of N) which converts to char const* but not to char*. In C++03 it was possible to convert to char* for backward compatibility but this rule is now gone. That is, your i needs to be declared char const*. As implemented above, your code tries to write read-only memory which will have undesirable effects.
The declaration of std::strcpy() takes a char* and a char const*: for the first pointer you need to provide sufficient space to hold a string of the second argument. Since this is error-prone it is a bad idea to use strcpy() in the first place! Instead, you want to replicate std::strncpy() which takes as third argument the length of the first buffer (actually, I'm never sure if std::strncpy() guarantees zero termination or not; you definitely also want to guarantee zero termination).
It is a bad idea to use strlen() in the loop condition as the function needs to be evaluated for each iteration of the loop, effectively changing the complexity of strlen() from linear (O(N)) to quadratic (O(N2)). Quadratic complexity is very bad. Copying a string of 1000 characters takes 1000000 operations. If you want to try out the effect, copy a string with 1000000 characters using a linear and a quadratic algorithm.
Your strcpy() doesn't add a null-terminator.
In C++ (and in C since ~1990) the implicit int rule doesn't apply. That is, you really need to write int in front of main().
OK, a couple of things:
you are missing the return type for the main function
declaration. Not really allowed under the standard. Some compilers will still allow it, but others will fail on the compile.
the way you have your for loop structured in
strcpy you are calling your strlen function each time through
the loop, and it is having to re-count the characters in the source
string. Not a big deal with a string like "ABC " but as strings get
longer.... Better to save the value of the result into a variable and use that in the for loop
Because of the way that you are declaring i in
`main' you are pointing to read-only storage, and will be causing an
access violation
Look at the other answers here for how to rebuild your code.
Pointer use in C and C++ is a perennial issue. I'd like to suggest the following tutorial from Paul DiLorenzo, "Learning C++ Pointers for REAL dummies.".
(This is not to imply that you are a "dummy," it's just a reference to the ",insert subject here> for Dummies" lines of books. I would not be surprised that the insertion of "REAL" is to forestall lawsuits over trademarked titles)
It is an excellent tutorial.
Hope it helps.
I have some function that needs to return a const char* (so that a whole host of other functions can end up using it).
I know that if I had something defined as follows:
const char* Foo(int n)
{
// Some code
.
.
.
return "string literal, say";
}
then there is no problem. However am I correct in saying that if Foo has to return some string that can only be determined at runtime (depending on the parameter n, (where each n taking any value in [0, 2^31-1] uniquely determines a return string)) then I have to use the heap (or return objects like std::string which use the heap internally)?
std::string seems too heavyweight for what I want to accomplish (at least two functions will have to pass the parcel), and allocating memory inside Foo to be freed by the caller doesn't strike me as a safe way of going forward. I cannot (easily) pass in references to the objects that need this function, and not that I believe it is possible anyway but macro trickery is out of the question.
Is there something simple that I have not yet considered?
EDIT
Thanks to all for the answers, I'll go for std::string (I suppose in a roundabout fashion I was asking for confirmation that there is no way of hinting to the compiler that it should store the contents of some char[] in the same place that it stores string literals). As for "heavyweight" (and I'm pleasantly surprised that copying them isn't as wasteful as I thought) that wasn't the best way of putting it, perhaps "different" would have been closer to my initial apprehension.
If you mean that your function chooses between one of n known-at-compile-time strings, then you can just return a const char * to any one of them. A string literal has static storage duration in C and C++, meaning that they exist for the lifetime of the program. Therefore it is safe to return a pointer to one.
const char* choose_string(int n)
{
switch(n % 4)
{
case 0: return "zero";
case 1: return "one";
case 2: return "two";
case 3: return "three";
}
}
If your function dynamically generates a string at runtime, then you have to either pass in a (char *buf, int buf_length) and write the result into it, or return a std::string.
In C++, returning a std::string is probably the right answer (as several others have already said).
If you don't want to use std::string for some reason (say, if you were programming in C, but then you would have tagged the question that way), there are several options for "returning" a string from a function. None of them are pretty.
If you return a string literal, what you're really returning is a pointer to the first character of the array object associated with that string literal. That object has static storage duration (i.e., it exists for the entire execution of your program), so returning a pointer to it is perfectly safe. This is obviously inflexible.
You can allocate an array on the heap and return a pointer to it. That lets the called function determine how long it needs to be, but it places the burden on the caller to deallocate the memory when it's no longer needed.
You can return a pointer to (the first element of) a static array defined inside the function. This is inflexible in that the maximum length has to be determined at compile time. It also means that successive calls to the function will clobber the result. The asctime() function, defined in <time.h> <ctime> does this. (I once wrote a function that cycled through the elements of a static array of arrays, so that 6 successive calls would not clobber previous results, but the 7th would. That was probably overkill.)
You can require the caller to pass in a pointer to (the first element of) an array that the caller itself must allocate, probably along with a separate argument that specifies the length of the caller's array. This requires the caller to know how long the string might be, and probably to be able to handle the error of not reserving enough space.
And now you know why C++ provides library features like std::string that take care of all this stuff for you.
Incidentally, the phrase "variable string literal" doesn't make a lot of sense. If something is a literal, it's not variable. Probably "variable string" is what you meant.
The easiest solution might be to return a std::string.
If you want to avoid std::string, one alternative is to have the caller pass a char[] buffer to the function. You might also want to provide a function that can tell the caller how big of a buffer will be needed, unless an upper bound is known statically.
Use std::string, but if you really want... A common pattern used in C programming is to return the size of the final result, allocate a buffer, and call the function twice. (I apologize for the C style, you want a C solution I give a C solution :P )
size_t Foo(int n, char* buff, size_t buffSize)
{
if (buff)
{
// check if buffSize is large enough if so fill
}
// calculate final string size and return
return stringSize;
}
size_t size = Foo(x, NULL, 0); // find the size of the result
char* string = malloc(size); // allocate
Foo(x,string, size); // fill the buffer
(Donning asbestos suit)
Consider just leaking the memory.
const char* Foo(int n)
{
static std::unordered_map<int, const char*> cache;
if (!cache[n])
{
// Generate cache[n]
}
return cache[n];
}
Yup, this will leak memory. Up to 2^32 strings worth of them. But if you had the actual string literals, you would always have all 2^32 strings in memory (and clearly require a 64 bits build - just the \0 alone take 4GB!)
I am trying to create a non-recursive method to swap a c-style string. It throws an exception in the Swap method. Could not figure out the problem.
void Swap(char *a, char* b)
{
char temp;
temp = *a;
*a = *b;
*b = temp;
}
void Reverse_String(char * str, int length)
{
for(int i=0 ; i <= length/2; i++) //do till the middle
{
Swap(str+i, str+length - i);
}
}
EDIT: I know there are fancier ways to do this. But since I'm learning, would like to know the problem with the code.
It throws an exception in the Swap method. Could not figure out the problem.
No it doesn't. Creating a temporary character and assigning characters can not possibly throw an exception. You might have an access violation, though, if your pointers don't point to blocks of memory you own.
The Reverse_String() function looks OK, assuming str points to at least length bytes of writable memory. There's not enough context in your question to extrapolate past that. I suspect you are passing invalid parameters. You'll need to show how you call Reverse_String() for us to determine if the call is valid or not.
If you are writing something like this:
char * str = "Foo";
Reverse_String(str, 3);
printf("Reversed: '%s'.\n", str);
Then you will definitely get an access violation, because str points to read-only memory. Try the following syntax instead:
char str[] = "Foo";
Reverse_String(str, 3);
printf("Reversed: '%s'.\n", str);
This will actually make a copy of the "Foo" string into a local buffer you can overwrite.
This answer refers to the comment by #user963018 made under #André Caron's answer (it's too long to be a comment).
char *str = "Foo";
The above declares a pointer to the first element of an array of char. The array is 4 characters long, 3 for F, o & o and 1 for a terminating NULL character. The array itself is stored in memory marked as read-only; which is why you were getting the access violation. In fact, in C++, your declaration is deprecated (it is allowed for backward compatibility to C) and your compiler should be warning you as such. If it isn't, try turning up the warning level. You should be using the following declaration:
const char *str = "Foo";
Now, the declaration indicates that str should not be used to modify whatever it is pointing to, and the compiler will complain if you attempt to do so.
char str[] = "Foo";
This declaration states that str is a array of 4 characters (including the NULL character). The difference here is that str is of type char[N] (where N == 4), not char *. However, str can decay to a pointer type if the context demands it, so you can pass it to the Swap function which expects a char *. Also, the memory containing Foo is no longer marked read-only, so you can modify it.
std::string str( "Foo" );
This declares an object of type std::string that contains the string "Foo". The memory that contains the string is dynamically allocated by the string object as required (some implementations may contain a small private buffer for small string optimization, but forget that for now). If you have string whose size may vary, or whose size you do not know at compile time, it is best to use std::string.