I'm working on writing my own string class and am having trouble with overloading the += operator for a MyString being +='d to a char. I figured this would work but with no luck. Here's the implementation I tried. Any assistance on getting it to work correctly will be much appreciated.
MyString& MyString::operator +=(char c)
{
char derp[1] = {c};
strcat(value, derp);
return *this;
}
This is not going to work for several reasons:
derp is not a null-terminated array, which it has to be if you pass it as a parameter to strcat
There is no check that the buffer that value represents can actually hold more data; neither is there a facility to make sure that the buffer is always null-terminated (which again it needs to be because you are passing it to strcat)
Even if you correct the above, your string class will never be able to include the character \0 as part of a string value because that will be mistaken for a null terminator; in technical terms, your string class would not be "binary safe"; to fix this you need to drop strcat and similar functions entirely and switch to memcpy and friends
Apart from the above, overloading operator += like this allows for code such as
MyString str("foo");
foo += 80; // this compiles, but should it?
Finally, the str*** family of functions is going to get needlessly slower as your strings are getting larger (because they have to scan the string from the beginning each time in order to determine where it ends). Keeping your own length variable and switching to mem*** is going to fix this issue as well.
The use of strcat is incorrect as it requires a null terminated source string and is being provided with a buffer with no null terminator.
value will only be capable of holding a finite number of characters, and there is no attempt to increase the size of value.
Assuming value is large enough and you retain the length of the string inside your instance, I'd say:
value[size] = c;
value[size+1] = '\0';
Related
I'm trying to ask the user to enter a random word, but when I go to try to store it, the normal cin isn't working and just seems to be confusing ncurses. I've tried other functions like wgetstr() but it takes a char and not a string. I've been attempting multiple conversion functions like c_str() but nothing. Does anybody have any tips?
getstr() family of functions do return null-terminated strings, not just a single character. It's C library, there isn't any std::string type.
You must supply a suitable large buffer for the functions. It is more safe to use getnstr which limits the number of read characters.
char buffer[256];
int result = getnstr(buffer,sizeof(buffer)-1);//Make space for '\0'
assert(results!=-1);
buffer[sizeof(buffer)-1] = '\0'; // Force null-termination in the edge case.
size_t length = strlen(buffer);
I am not 100% sure whether the limit on n read characters includes the null byte, if it works as strncpy, it might not and in that case it's better to leave a space for it and add it explicitly.
I'm using a dynamic C-style string to read in data from a file, but for some reason when I dynamically allocate the C-style string using the given length, it comes out with four extra characters that can be seen using strlen(). The junk in these empty spaces is added on to the end of the read-in string and is displayed on cout. What on earth could be causing this, and how can I fix it?
The C-style string is declared in the beginning of the code, and is used one time before this. The time it is used before this it is also too large, but in that case it does not add extra information to the end. After use, it is deleted and not used again until this point. I'm pretty confused as I have not had this happen or had a problem with it before.
// Length read as 14, which is correct
iFile.read(reinterpret_cast<char *>(&length), sizeof(int));
tempCstring = new char[length]; // Length still 14
cout << strlen(tempCstring); // Console output: 18
// In tempCstring: Powerful Blockýýýý
iFile.read(reinterpret_cast<char *>(tempCstring), length);
// Custom String class takes in value Powerful Blockýýýý and is
// initialized to that
tempString = String(tempCstring);
// Temp character value takes in messed up string
temp.setSpecial(tempString);
delete[] tempCstring; // Temp cString is deleted for next use
When written to file:
// Length set to the length of the cString, m_special
length = strlen(chars[i].getSpecial().getStr());
// Length written to file. (Should I add 1 for null terminator?)
cFile.write(reinterpret_cast<char *>(&length), sizeof(int));
// String written to file
cFile.write(reinterpret_cast<char *>(chars[i].getSpecial().getStr()), length);
Whenever you see junk at the end of a string, the problem is almost always the lack of a terminator. Every C-style string ends in a byte whose value is zero, spelled '\0'. If you did not place one yourself, the standard library keeps reading bytes in memory until it sees a random '\0' that it sees in memory. In other words, the array is read beyond its bounds.
Use memset(tempCString,0,length) in order to zero out the memory following your allocation. However, this is not the soundest solution, as it is covering the real problem under the rug. Show us the context in which this code is used. Then I will be able to say where in your algorithm you will need to insert the null terminator: tempCString[i] = 0, or something like that. Nonetheless, from what you have posted, I can tell that you need to allocate one more character to make room for the terminator.
Also, since you are using C++, why not use std::string? It avoids these kinds of problems.
This is a fairly basic question and I am pretty sure I know the answer, but seeing as the consequence for being wrong is a segfault I figure I should ask. I have been using strlen() and the new char[] operator in the following way for quite some time now and just noticed something that threw up a red flag:
void genericCopy(char *somestring, char *someOtherString) {
someOtherString = new char[strlen(somestring)];
strcpy(someOtherString,somestring);
}
My question is, seeing as a string should be null terminated, should I be doing this as such:
void genericCopy(char *somestring, char *someOtherString) {
someOtherString = new char[strlen(somestring)+1];
strcpy(someOtherString,somestring);
someOtherString[strlen(someOtherString)] = '\0';
}
So far I have never had a problem with the first method, but that doesn't mean I'm doing it right. Since the length being return by strlen()is the number of characters in the string without the null terminator so new isn't reserving space for '/0'... At least I don't think it is.
First of all, you should know that this function of yours is pointless to write, just use strdup (if available on your system).
But yes, you need an additional byte to store the \0, so always do something like new char[strlen(somestring)+1];. However, there is no need to manually add the \0; strcpy already does this.
You should use something like Valgrind to discover this and similar bugs in your code.
There is however an additional problem in your code; your code will always leak someOtherString; it will not be returned to where you called it from. You either need to change your method to something like:
char *genericCopy(char *something) {
char *copy = new char[strlen(somestring)+1];
strcpy(copy,somestring);
return copy;
}
and then get the copy as follows:
copy = genericCopy(something);
Or you need to change your method to something like:
void genericCopy(char *something, char **copy) {
*copy = new char[strlen(somestring)+1];
strcpy(*copy,somestring);
}
and call it as:
genericCopy(something, ©);
If you'll be using C++ you could also just change the method prototype to:
void genericCopy(char* somestring, char*& someOtherString)
and call it as:
genericCopy(something, copy);
Then someOtherString will be passed as a reference, and the new value you allocate to it will propagate outside of your method.
Yes, your suspicion is correct. You should be allocating an additional character, and making sure the copied string is null-terminated. (strcpy() itself will do this, but when someone advises to you that you switch to strncpy(), as they no doubt will (it's safer!) you'll need to be extra careful, because it is NOT guaranteed to copy the '/0'.)
If you're already using C++, though, you may be well-advised to switch to using std::string. It's often an easier, less error-prone method of manipulating character arrays.
However, here's the further problem that you need to address. You are assigning your new character array to a COPY of someOtherString. You need to make some changes:
void genericCopy(char *somestring, char **someOtherString) {
*someOtherString = new char[strlen(somestring)+1];
strcpy(*someOtherString,somestring);
(*someOtherString)[strlen(somestring)] = '\0';
}
This way you will get back the new character buffer outside your function call.
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.
I wrote the following code:
char *pch=new char[12];
char *f=new char[42];
char *lab=new char[20];
char *mne=new char[10];
char *add=new char[10];
If initially I want these arrays to be null, can't I do this:
*lab="\0";
*mne="\0";
and so on.....
And after that if I want to add some cstring to an empty array can't I check:
if(strcmp(lab,"\0")==0)
//then add cstring by *lab="cstring";
And if I can't do any of these things, please tell me the right way to do it...
In C++11, an easy way to initialize arrays is by using brace-initializers:
char * p = new char[100] { 0 };
The reasoning here is that all the missing array elements will be zero-initialized. You can also use explicit value-initialization (I think that's even allowed in C++98/03), which is zero-initalization for the primitive types:
char * q = new char[110]();
First of all, as DeadMG says, the correct way of doing this is using std:string:
std::string lab; // empty initially, no further initialization needed
if (lab.size() == 0) // string empty, note, very fast, no character comparison
lab += "cstring"; // or even lab = "cstring", as lab is empty
Also, in your code, if you insist in using C strings, after the initialization, the correct checking for the empty string would be
if (*lab == '\0')
First of all, I agree with everybody else to use a std::string instead of character arrays the vast majority of the time. Link for help is here: C++ Strings Library
Now to directly answer your question as well:
*lab="\0";
*mne="\0";
and so on.....
This is wrong. Assuming your compiler doesn't give you an error, you're not assigning the "null terminator" to those arrays, you're trying to assign the pointer value of where the "\0" string is to the first few memory locations where the char* is pointing to! Remember, your variables are pointers, not strings. If you're trying to just put a null-character at the beginning, so that strlen or other C-string functions see an "empty" string, do this: *lab='\0'; The difference is that with single-ticks, it denotes the character \0 whereas with double, it's a string literal, which returns a pointer to the first element. I hope that made sense.
Now for your second, again, you can't just "assign" like that to C-style strings. You need to put each character into the array and terminate it correctly. Usually the easiest way is with sprintf:
sprintf(lab, "%s", "mystring");
This may not make much sense, especially as I'm not dereferencing the pointer, but I'll walk you through it. The first argument says to sprintf "output your characters to where this pointer is pointing." So it needs the raw pointer. The second is a format string, like printf uses. So I'm telling it to use the first argument as a string. And the 3rd is what I want in there, a pointer to another string. This example would also work with sprintf(lab, "mystring") as well.
If you want to get into C-style string processing, you need to read some examples. I'm afraid I don't even know where to look on the 'net for good examples of that, but I wish you good luck. I'd highly recommend that you check out the C++ strings library though, and the basic_string<> type there. That's typedef'd to just std::string, which is what you should use.