Ps: This is more of a conceptual question.
I know this makes things more complicated for no good reason, but here is what I'm wondering. If I'm not mistaken, a const char* "like this" in c++ is pointing to l and will be automatically zero terminated on compile time. I believe it is creating a temporary variable const char* to hold it, unless it is keeping track of the offset using a byte variable (I didn't check the disassembly). My question is, how would you if even possible, add characters to this string without having to call functions or instantiating strings?
Example (This is wrong, just so you can visualize what I meant):
"Like thi" + 's';
The closest thing I came up with was to store it to a const char* with enough spaces and change the other characters.
Example:
char str[9];
strcpy(str, "Like thi")
str[8] = 's';
Clarification:
Down vote: This question does not show any research effort; it is unclear or not useful
Ok, so the question has been highly down voted. There wasn't much reasoning on which of these my question was lacking on, so I'll try to improve all of those qualities.
My question was more so I could have a better understanding of what goes on when you simply create a string "like this" without storing the address of that string in a const char* I also wanted to know if it was possible to concatenate/change the content of that string without using functions like strcat() and without using the overloaded operator + from the class string. I'm aware this is not exactly useful for dealing with strings in C++, but I was curious whether or not there was a way besides the standard ways for doing so.
string example = "Like thi" + "s"; //I'm aware of the string class and its member functions
const char* example2 = "Like this"; //I'm also aware of C-type Strings (CString as well)
It is also possible that not having English as my native language made things even worst, I apologize for the confusion.
Instead of using a plain char string, you should use the string library provided by the C++ library:
#include <string>
#include <iostream>
using namespace std;
int main()
{
string str = "Like thi";
cout << str << endl;
str = str + "s";
cout << str << endl;
return 0;
}
Normally, it's not possible to simply concatenate plain char * strings in C or C++, because they are merely pointers to arrays of characters. There's almost no reason you should be using a bare character array in C++ if you intend on doing any string manipulations within your own code.
Even if you need access to the C representation (e.g. for an external library) you can use string::c_str().
First, there is nothing null terminated, but the zero terminated. All char* strings in C end with '\0'.
When you in code do something like this:
char *name="Daniel";
compiler will generate a string that has a contents:
Daniel\0
and will initialize name pointer to point at it at a certain time during program execution depending on the variable context (member, static, ...).
Appending ANYTHING to the name won't work as you expect, since memory pointed to by name isn't changeable, and you'll probably get either access violation error or will overwrite something else.
Having
const char* copyOfTheName = name;
won't create a copy of the string in question, it will only have copyOfTheName point to the original string, so having
copyOfTheName[6]='A';
will be exactly as
name[6]='A';
and will only cause problems to you.
Use std::strcat instead. And please, do some investigating how the basic string operations work in C.
Related
My knowledge till now was that arrays in C and CPP/C++ have fixed sizes. However recently I encountered 2 pieces of code which seems to contradict this fact. I am attaching the pics here. Want to hear everyone's thoughts on how these are working. Also pasting the code and doubts here:
1.
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
char str1[]="Good"; //size of str1 should be 5
char str2[]="Afternoon"; //size of str2 should be 10
cout<<"\nSize of str1 before the copy: "<<sizeof(str1);
cout<<"\nstr1: "<<str1;
strcpy(str1,str2); //copying str1 into str2
cout<<"\nSize of str1 after the copy: "<<sizeof(str1);
cout<<"\nstr1: "<<str1;
return 0;
}
your text
O/P:
Size of str1 before the copy: 5
str1: Good
Size of str1 after the copy: 5
str1: Afternoon
In first snippet I am using strcpy to copy char str2[] contents that is "Afternoon" into char str1[] whose size is 5 less than size of str2. So theoritically the line strcpy(str1,str2) should give error as size of str1 is less than size of str2 and fixed. But it executes, and more surprising is the fact that even after str1 contain the word "afternoon" the size is still the same.
2.
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char first_string[10]; // declaration of char array variable
char second_string[20]; // declaration of char array variable
int i; // integer variable declaration
cout<<"Enter the first string: ";
cin>>first_string;
cout<<"\nEnter the second string: ";
cin>>second_string;
for(i=0;first_string[i]!='\0';i++);
for(int j=0;second_string[j]!='\0';j++)
{
first_string[i]=second_string[j];
i++;
}
first_string[i]='\0';
cout<<"After concatenation, the string would look like: "<<first_string;
return 0;
}
O/P:
Enter the first string: good
Enter the second string: afternoon
After concatenation, the string would look like: goodafternoon
Here also even if I provide a string of length 20 as input to second_string[] it's still able to concatenate both the strings and put them in first_string[], even though the size of the concatenated string will be clearly greater than size of first_string[] which is 10.
I tried to assign a string of greater length to a string variable of smaller length. techincally it should not work but it worked anyway
There are two misunderstandings here
sizeof is the size of the array at compile time. It has nothing to do with the contents of the array. You can change the contents all you like and sizeof will still be the same. If you want the length of a string use the function strlen.
Most of the time when you break the rules of C++ it leads to undefined behaviour. Copying a string into an array that is too small to hold that string is one example of undefined behaviour.
You said
So theoritically the line strcpy(str1,str2) should give error as size
of str1 is less than size of str2 and fixed.
This is untrue. Undefined behaviour does not mean that there must be an error. It means exactly what it says, the behaviour of your program is undefined, anything could happen. That might mean an error message, or it might mean a crash, or it might mean that your program seems to work. The behaviour is undefined.
You aren't alone in thinking as you did. I reckon the purpose of sizeof and the nature of undefined behaviour are two of the commonest beginner misunderstandings.
And to answer the question in the title. The size of a character array is fixed in C++, nothing in your example contradicts that.
I've honestly never seen a C++ programmer write char stringname[20] = "string";, that just isn't the way you'd handle strings in C++⁰.
And neither would a C programmer use array notation, because well, it's just not common; you'd typically use arrays for things that aren't strings, even if the type of a "string literal" is actually char[length + 1].
Your access beyond the end of an array is simply a bug. It is undefined behaviour. A buffer overflow. A static code analyzer, quite possibly even a compiler, would tell you that this is a mortal sin. The str* functions know literally nothing about the size of your array, they only see a pointer to the first element, and your array literally knows nothing about the length of the string it contains, which is given by the terminating zero character's position. You're mixing up two things here!
In C++, you'd definitely use the std::string class to read from cin, exactly to avoid the problem with buffer overflows.
So, honestly: If you're a C++ beginner, maybe try to ignore C strings for now. It's not a C++ way of dealing with string data other than fixed string literals (i.e., things between "" in your source code), and the C way of string handling is literally still the dominant cause for remote-exploitable bugs in software, far as I can tell. C++ is not C, and, honestly, when it comes to handling strings, for the better. Including both <string.h> and <iostreams> is a pretty reliable indication of a programming beginner who has access to bad guides that treat C++ as extended C. But that's simply not true; it's a very different programming language with some far-reaching C compatibility, but you would, and should, not mix these two languages – as a beginner, it's hard enough to learn one¹.
⁰ Technically speaking, it even feels wrong; a string literal in C++ is a const char pointer, whereas it's just a char pointer in C. C and C++ are not the same language.
¹If you feel like you're explaining C++ to people, and sometimes feel overwhelmed with making a good explanation for things to people who are not expert C programmers already, Kate Gregory made a nice talk why teaching C to teach C++ is a really bad idea, which I agree to, even if she overstresses a few points.
Many topics have discussed the difference between string and char[]. However, they are not clear to me to understand why we need to bring string in c++? Any insight is welcome, thanks!
char[] is C style. It is not object oriented, it forces you as the programmer to deal with implementation details (such as '\0' terminator) and rewrite standard code for handling strings every time over and over.
char[] is just an array of bytes, which can be used to store a string, but it is not a string in any meaningful way.
std::string is a class that properly represents a string and handles all string operations.
It lets you create objects and keep your code fully OOP (if that is what you want).
More importantly, it takes care of memory management for you.
Consider this simple piece of code:
// extract to string
#include <iostream>
#include <string>
main ()
{
std::string name;
std::cout << "Please, enter your name: ";
std::cin >> name;
std::cout << "Hello, " << name << "!\n";
return 0;
}
How would you write the same thing using char[]?
Assume you can not know in advance how long the name would be!
Same goes for string concatenation and other operations.
With real string represented as std::string you combine two strings with a simple += operator. One line.
If you are using char[] however, you need to do the following:
Calculate the size of the combined string + terminator character.
Allocate memory for the new combined string.
Use strncpy to copy first string to new array.
Use strncat to append second string to first string in new array.
Plus, you need to remember not to use the unsafe strcpy and strcat and to free the memory once you are done with the new string.
std::string saves you all that hassle and the many bugs you can introduce while writing it.
As noted by MSalters in a comment, strings can grow. This is, in my opinion, the strongest reason to have them in C++.
For example, the following code has a bug which may cause it to crash, or worse, to appear to work correctly:
char message[] = "Hello";
strcat(message, "World");
The same idea with std::string behaves correctly:
std::string message{"Hello"};
message += "World";
Additional benefits of std::string:
You can send it to functions by value, while char[] can only be sent by reference; this point looks rather insignificant, but it enables powerful code like std::vector<std::string> (a list of strings which you can add to)
std::string stores its length, so any operation which needs the length is more efficient
std::string works similarly to all other C++ containers (vector, etc) so if you are already familiar with containers, std::string is easy to use
std::string has overloaded comparison operators, so it's easy to use with std::map, std::sort, etc.
String class is no more than an amelioration of the char[] variable.
With strings you can achieve the same goals than the use of a char[] variable, but you won't have to matter about little tricks of char[] like pointers, segmentation faults...
This is a more convenient way to build strings, but you don't really see the "undergrounds" of the language, like how to implement concatenation or length functions...
Here is the documentation of the std::string class in C++ : C++ string documentation
I'm trying to instantiate and easily access an array of names in C++ using basic types in contiguous memory. I'm astounded that this is extremely difficult or complicated to do in C++ WITH ONLY basic types.
For some background, I am programming a microcontroller with limited memory, modest processing power, and it is handling serial communication over a network to 36 other microcontrollers sending continuous sensor data which is uploaded to a webserver. The shorter the refresh rate of the data, the better, so I prefer basic program features.
Not that I'm saying the more complicated stuff I've looked in other forums for, like an array of strings, has worked.
In my desperation, I was able to get this to work.
char names_array[] = "Bob\0\0Carl";
printf("%s",names_array); //outputs Bob
printf("%s",names_array + 5); //outputs Carl
This is a horrible solution though. My indexing is dependent on the longest name in the array, so if I added "Megan" to my list of names, I'd have to add a bunch of null characters throughout the entire array.
What I want to do is something like this:
char names_array[2] = {"Bob","Carl"}; //does not compile
printf("%s",names_array[0]);
printf("%s",names_array[1]);
//Error: A value of type "const char *" cannot be used to
//initialize an entity of type "char" in "main.cpp"
but that didn't work.
I want to loop through the names in my list and do something with each name, so at this point, this is my best solution.
char name0[] = "Bob";
loop_code(name0);
char name1[] = "Carl";
loop_code(name1);
.
.
.
I expect there's a reasonable way to make an array of pointers, each to an array of char terminated by null(s). I must be doing something wrong. I refuse to believe that a language like C++ is incapable of such a basic memory allocation.
You can, e.g., get an array of pointers to null-terminated strings:
const char* names_array[] = { "Bob", "Carl" };
and then
std::printf("%s", names_array[0]);
std::printf("%s", names_array[1]);
The problem with your attempt
char names_array[2] = {"Bob","Carl"};
is that you declare names_array to be an array of characters. This should never compile because what the = {"Bob","Carl"} essentially attempts to do is initialize each character in that array of characters with an entire array of characters of its own. A character is just a character, you cannot assign an entire array of characters to just an individual character. More precisely, initialization of a character array from a string literal is a special case of initialization [dcl.init.string] that allows a single string literal to be used to initialize an entire character array (because anything else doesn't make sense). What you actually want would be something more like an array of character arrays. However, the problem there is that you'd have to effectively pick a fixed maximum length for all strings in the array:
char names_array[][5] = { "Bob", "Carl" }; // each subarray is 5 characters in length
which would be potentially wasteful. You can flatten a series of multiple strings into one long array and then index into that, like you did with your first approach. The downside of that, as you've found out, is that you then need to know where each string starts in that array…
If you just want an array of string constants, a more modern C++ approach would be something like this:
#include <string_view>
using namespace std::literals;
constexpr std::string_view names[] = {
"Bob"sv,
"Carl"sv
};
The advantage of std::string_view is that it also has information about the length of the string. However, while std::string_view is compatible with most of the C++ standard library facilities that handle strings, it's not so simple to use it together with functions that expect C-style null-terminated strings. If you need null-terminated strings, I'd suggest to simply use an array of pointers to strings as shown at the very beginning of this answer…
char can has only one character.
If you want to use char, you can do it like
char name0[3] = "Bob";
char name1[4] = "Carl";
char *nameptr[2] = {&name0[0], &name1[0]};
Acutally, this pretty hard.
I suggest to you, use std::string.
std::string name[2] = {"Bob","Carl"};
this code is acceptable.
tl:dr
How can I concatenate const char* with std::string, neatly and
elegantly, without multiple function calls. Ideally in one function
call and have the output be a const char*. Is this impossible, what
is an optimum solution?
Initial Problem
The biggest barrier I have experienced with C++ so far is how it handles strings. In my opinion, of all the widely used languages, it handles strings the most poorly. I've seen other questions similar to this that either have an answer saying "use std::string" or simply point out that one of the options is going to be best for your situation.
However this is useless advice when trying to use strings dynamically like how they are used in other languages. I cannot guaranty to always be able to use std::string and for the times when I have to use const char* I hit the obvious wall of "it's constant, you can't concatenate it".
Every solution to any string manipulation problem I've seen in C++ requires repetitive multiple lines of code that only work well for that format of string.
I want to be able to concatenate any set of characters with the + symbol or make use of a simple format() function just how I can in C# or Python. Why is there no easy option?
Current Situation
Standard Output
I'm writing a DLL and so far I've been output text to cout via the << operator. Everything has been going fine so far using simple char arrays in the form:
cout << "Hello world!"
Runtime Strings
Now it comes to the point where I want to construct a string at runtime and store it with a class, this class will hold a string that reports on some errors so that they can be picked up by other classes and maybe sent to cout later, the string will be set by the function SetReport(const char* report). So I really don't want to use more than one line for this so I go ahead and write something like:
SetReport("Failure in " + __FUNCTION__ + ": foobar was " + foobar + "\n"); // __FUNCTION__ gets the name of the current function, foobar is some variable
Immediately of course I get:
expression must have integral or unscoped enum type and...
'+': cannot add two pointers
Ugly Strings
Right. So I'm trying to add two or more const char*s together and this just isn't an option. So I find that the main suggestion here is to use std::string, sort of weird that typing "Hello world!" doesn't just give you one of those in the first place but let's give it a go:
SetReport(std::string("Failure in ") + std::string(__FUNCTION__) + std::string(": foobar was ") + std::to_string(foobar) + std::string("\n"));
Brilliant! It works! But look how ugly that is!! That's some of the ugliest code I've every seen. We can simplify to this:
SetReport(std::string("Failure in ") + __FUNCTION__ + ": foobar was " + std::to_string(foobar) + "\n");
Still possibly the worst way I've every encounter of getting to a simple one line string concatenation but everything should be fine now right?
Convert Back To Constant
Well no, if you're working on a DLL, something that I tend to do a lot because I like to unit test so I need my C++ code to be imported by the unit test library, you will find that when you try to set that report string to a member variable of a class as a std::string the compiler throws a warning saying:
warning C4251: class 'std::basic_string<_Elem,_Traits,_Alloc>' needs to have dll-interface to be used by clients of class'
The only real solution to this problem that I've found other than "ignore the warning"(bad practice!) is to use const char* for the member variable rather than std::string but this is not really a solution, because now you have to convert your ugly concatenated (but dynamic) string back to the const char array you need. But you can't just tag .c_str() on the end (even though why would you want to because this concatenation is becoming more ridiculous by the second?) you have to make sure that std::string doesn't clean up your newly constructed string and leave you with garbage. So you have to do this inside the function that receives the string:
const std::string constString = (input);
m_constChar = constString.c_str();
Which is insane. Because now I traipsed across several different types of string, made my code ugly, added more lines than should need and all just to stick some characters together. Why is this so hard?
Solution?
So what's the solution? I feel that I should be able to make a function that concatenates const char*s together but also handle other object types such as std::string, int or double, I feel strongly that this should be capable in one line, and yet I'm unable to find any examples of it being achieved. Should I be working with char* rather than the constant variant, even though I've read that you should never change the value of char* so how would this help?
Are there any experienced C++ programmers who have resolved this issue and are now comfortable with C++ strings, what is your solution? Is there no solution? Is it impossible?
The standard way to build a string, formatting non-string types as strings, is a string stream
#include <sstream>
std::ostringstream ss;
ss << "Failure in " << __FUNCTION__ << ": foobar was " << foobar << "\n";
SetReport(ss.str());
If you do this often, you could write a variadic template to do that:
template <typename... Ts> std::string str(Ts&&...);
SetReport(str("Failure in ", __FUNCTION__, ": foobar was ", foobar, '\n'));
The implementation is left as an exercise for the reader.
In this particular case, string literals (including __FUNCTION__) can be concatenated by simply writing one after the other; and, assuming foobar is a std::string, that can be concatenated with string literals using +:
SetReport("Failure in " __FUNCTION__ ": foobar was " + foobar + "\n");
If foobar is a numeric type, you could use std::to_string(foobar) to convert it.
Plain string literals (e.g. "abc" and __FUNCTION__) and char const* do not support concatenation. These are just plain C-style char const[] and char const*.
Solutions are to use some string formatting facilities or libraries, such as:
std::string and concatenation using +. May involve too many unnecessary allocations, unless operator+ employs expression templates.
std::snprintf. This one does not allocate buffers for you and not type safe, so people end up creating wrappers for it.
std::stringstream. Ubiquitous and standard but its syntax is at best awkward.
boost::format. Type safe but reportedly slow.
cppformat. Reportedly modern and fast.
One of the simplest solution is to use an C++ empty string. Here I declare empty string variable named _ and used it in front of string concatenation. Make sure you always put it in the front.
#include <cstdio>
#include <string>
using namespace std;
string _ = "";
int main() {
char s[] = "chararray";
string result =
_ + "function name = [" + __FUNCTION__ + "] "
"and s is [" + s + "]\n";
printf( "%s", result.c_str() );
return 0;
}
Output:
function name = [main] and s is [chararray]
Regarding __FUNCTION__, I found that in Visual C++ it is a macro while in GCC it is a variable, so SetReport("Failure in " __FUNCTION__ "; foobar was " + foobar + "\n"); will only work on Visual C++. See: https://msdn.microsoft.com/en-us/library/b0084kay.aspx and https://gcc.gnu.org/onlinedocs/gcc/Function-Names.html
The solution using empty string variable above should work on both Visual C++ and GCC.
My Solution
I've continued to experiment with different things and I've got a solution which combines tivn's answer that involves making an empty string to help concatenate long std::string and character arrays together and a function of my own which allows single line copying of that std::string to a const char* which is safe to use when the string object leaves scope.
I would have used Mike Seymour's variadic templates but they don't seem to be supported by the Visual Studio 2012 I'm running and I need this solution to be very general so I can't rely on them.
Here is my solution:
Strings.h
#ifndef _STRINGS_H_
#define _STRINGS_H_
#include <string>
// tivn's empty string in the header file
extern const std::string _;
// My own version of .c_str() which produces a copy of the contents of the string input
const char* ToCString(std::string input);
#endif
Strings.cpp
#include "Strings.h"
const std::string str = "";
const char* ToCString(std::string input)
{
char* result = new char[input.length()+1];
strcpy_s(result, input.length()+1, input.c_str());
return result;
}
Usage
m_someMemberConstChar = ToCString(_ + "Hello, world! " + someDynamicValue);
I think this is pretty neat and works in most cases. Thank you everyone for helping me with this.
As of C++20, fmtlib has made its way into the ISO standard but, even on older iterations, you can still download and use it.
It gives similar capabilities as Python's str.format()(a), and your "ugly strings" example then becomes a relatively simple:
#include <fmt/format.h>
// Later on, where code is allowed (inside a function for example) ...
SetReport(fmt::format("Failure in {}: foobar was {}\n", __FUNCTION__, foobar));
It's much like the printf() family but with extensibility and type safety built in.
(a) But, unfortunately, not its string interpolation feature (use of f-strings), which has the added advantage of putting the expressions in the string at the place where they're output, something like:
set_report(f"Failure in {__FUNCTION__}: foobar was {foobar}\n");
If fmtlib ever got that capability, I'd probably wet my pants in excitement :-)
I have a function for writing ppm files (a picture format) to disk. It takes the filename as a char* array. In my main function, I put together a filename using a stringstream and the << operator. Then, I want to pass the results of this to my ppm function. I've seen this discussed elsewhere, often with very convoluted looking methods (many in-between conversion steps).
What I've done is shown in the code below, and the tricky part that others usually do in many steps with temp variables is (char*) (PPM_file_name.str().data()). What this accomplishes is to extract the string from stringstream PPM_file_name with .str(), then get the pointer to its actual contents with .data() (this is a const char*), then cast that to a regular (char*). More complete example below.
I've found the following to work fine so far, but it makes me uneasy because usually when other people have done something in a seemingly more convoluted way, it's because that's a safer way to do it. So, can anyone tell me if what I'm doing here is safe and also how portable is it?
Thanks.
#include <iostream>
#include <sstream>
#include <stdio.h>
#include <string>
using namespace std;
int main(int argc, char *argv[]){
// String stream to hold the file name so I can create it from a series of other variable
stringstream PPM_file_name;
// ... a bunch of other code where int ccd_num and string cur_id_str are created and initialized
// Assemble the file name
PPM_file_name << "ccd" << ccd_num << "_" << cur_id_str << ".ppm";
// From PPM_file_name, extract its string, then the const char* pointer to that string's data, then cast that to char*
write_ppm((char*)(PPM_file_name.str().data()),"ladybug_vidcapture.cpp",rgb_images[ccd_num],width,height);
return 0;
}
Thanks everyone. So, following a few peoples' suggestions here, I've done the following, since I do have control over write_ppm:
Modified write_ppm to take const char*:
void write_ppm(const char *file_name, char *comment, unsigned char *image,int width,int height)
And now I'm passing ppm_file_name as follows:
write_ppm((PPM_file_name.str().c_str()),"A comment",rgb_images[ccd_num],width,height);
Is there anything I should do here, or does that mostly clear up the issues with how this was being passed before? Should all the other char arguments to write_ppm be const as well? It's a very short function, and it doesn't appear to modify any of the arguments. Thanks.
This looks like a typical case of someone not writing const-correct code and it having the knock-on effect. You have several choices:
If write_ppm is under your control, or the control of anyone you know, get them to make it const corrct
If it is not, and you can guarantee it never changes the filename then const_cast
If you cannot guarantee that, copy your string into a std::vector plus the null terminator and pass &vec[0] (where vec represents the name of your vector variable)
You should use PPM_file_name.str().c_str(), since data() isn't guaranteed to return a null-terminated string.
Either write_ppm() should take its first argument by const char* (promising not to change the string's content) or you must not pass a string stream (because you must not change its content that way).
You shouldn't use C-style casts in C++, because they don't differentiate between different reasons to cast. Yours is casting away const, which, if at all, should be done using const_cast<>. But as a rule of thumb, const_cast<> is usually only required to make code compile that isn't const-correct, which I'd consider an error.
It's absolutely safe and portable as long as write_ppm doesn't actually change the argument, in which case it is undefined behavior. I would recommend using const_cast<char*> instead of C-style cast. Also consider using c_str() member instead of the data() member. The former guarantees to return a null-terminated string
Use c_str() instead of data() (c_str() return a NULL-terminated sequence of characters).
Why not simply use const_cast<char *>(PPM_file_name.str().c_str()) ?