C-String implementation in C++ outputs incorrectly - c++

I was recently working on a problem teaching new users of C++, which I myself am, how to use cstrings and the different implementations of them compared to the imported string object in C++. As I was working on the problem, I came across an error where, despite initializing the size of the cstring to an appropriate length for the operations that were being done, the cstring was being outputted strangely.
When I would go to print out the cstring using cout, it would print some of the cstring correctly, but oftentimes the first several characters were random characters that had nothing to do with the operations being done to the cstring. However, I found a way to definitively prevent those characters from being printed; however, I am curious as to why this works as well as what the issue is here.
I found that adding cout << ""; on its own line prior to printing the cstring resolved the issue of the random characters being outputted when printing the cstring. However, this seems like only a temporary fix and I am looking to find a more educated approach to solving this issue.
Below I have included the code that was causing the errors.
#include <iostream>
#include <vector>
#include <string>
#include <cstring>
using namespace std;
int main() {
vector<string> words = {"Hello,", "and", "welcome", "to", "the", "world", "of", "C++!"};
// Calculate the total number of characters in the words vector
// (including an additional character for space)
int length = 0;
for(int i = 0; i < words.size(); i++) {
length += words.at(i).length() + 1;
}
cout << ""; // Removing this line of code will cause the output to do strange things
// Initialize the cstring to be of size length
char cstring[length];
// Build the cstring using cstring library functions
for(int i = 0; i < words.size(); i++) {
strcat(cstring, (words.at(i) + " ").c_str());
}
// Null-terminate the cstring
cstring[length-1] = '\0';
// Output the cstring
cout << cstring << " " << strlen(cstring) << endl;
return 0;
}
If the line of code containing cout << ""; is removed, the output looks something like this, with a random amount and random set of characters at the beginning of the output each time:
`k+��Hello, and welcome to the world o 39
However, by including the line, I am able to achieve the desired output:
Hello, and welcome to the world of C++! 39

For starters variable length arrays is not a standard C++ feature
// Initialize the cstring to be of size length
char cstring[length];
Secondly you defined an uninitialized array. So using strcat invokes undefined behavior
strcat(cstring, (words.at(i) + " ").c_str());
This statement
// Null-terminate the cstring
cstring[length-1] = '\0';
is redundant because the function strcat appends also the terminating zero provided that the character array you declared has a space to accommodate the zero character (and you forgot to reserve a space for the terminating zero in the array).
If the compiler supports variable length arrays then the program can look the following way
#include <iostream>
#include <string>
#include <vector>
#include <cstring>
int main()
{
std::vector<std::string> words =
{
"Hello,", "and", "welcome", "to", "the", "world", "of", "C++!"
};
// Calculate the total number of characters in the words vector
// (including an additional character for space)
size_t length = words.size();
for ( const auto &s : words ) length += s.length();
// Initialize the cstring to be of size length
char cstring[length + 1];
cstring[0] = '\0';
// Build the cstring using cstring library functions
for ( const auto &s : words )
{
std::strcat( cstring, ( s + ' ' ).c_str() );
}
// Output the cstring
std:: cout << cstring << ' ' << length << std::endl;
return 0;
}
The program output is
Hello, and welcome to the world of C++! 40

Related

String Altering Program Outputting Random Characters

#include "stdafx.h"
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
string output;
string words;
int i;
int main()
{
cin >> words; // gets words from user
output = ""; // readys the output string
i = 0; // warms up the calculator
int size = words.size(); // size matters
while (i <= size) { // loops through each character in "words" (can't increment in the function?)
output += ":regional_indicator_" + words[i] +':'; // appends output with each letter from words plus a suffix and prefix
++i;
}
cout << output << endl; // prints the output
return 0;
}
My intentions with this code is decently clear I'd like to think. Simply take a sentence, replace all characters with that character + a suffix and prefix.
My problem is that, when ran in the debugger, I'll input "hello world" and the program will output "osss".
I have absolutely no education in C++ and am at a total loss here. Is it my ++i?
This line:
output += ":regional_indicator_" + words[i] +':'; // appends output with each letter from words plus a suffix and prefix
doesn't work. The overloading of the + operator for string concatenation only works if one of the arguments is a std::string. But you're trying to use it with a C-string literal and a char. Change that to:
output += "regional_indicator_";
output += words[i];
output += ':';
This uses the += overloading of std::string for each part, and does what you want.
Also, if you want to read a whole line, not just a single word, use:
getline(cin, words);

strncpy function not working for me correctly

I'm kind of just starting in C++ so I might have a dumb mistake here. Below is my code along with outputs in the comments. I'm using Xcode.
#include <iostream>
#include <string.h>
using namespace std;
int main() {
char myString[] = "Hello There";
printf("%s\n", myString);
strncpy(myString, "Over", 5); // I want this to print out "Over There"
cout<< myString<<endl; // this prints out ONLY as "Over"
for (int i = 0; i <11; i++){
cout<< myString[i];
}// I wanted to see what's going on this prints out as Over? There
// the ? is upside down, it got added in
cout<< endl;
return 0;
}
THE PROBLEM
strncpy (destination, source, max_len)
strncpy is defined to copy at most max_len characters from source to destination, including the trailing null-byte if source doesn't include a null-byte within the first max_len bytes.
In your case the trailing null-byte will be including, and with that destination will be null-terminated directly after "Over", which is why you are seeing the described behaviour.
After your call to strncpy myString will therefore compare equal to:
"Over\0There"
THE SOLUTION
The most straight-forward solution would be to not copy the trailing null-byte from "Over", which is as easy as specifying 4 instead of 5 to strncpy:
strncpy(myString, "Over", 4);
The documentation for strncopy is as follows:
char * strncpy ( char * destination, const char * source, size_t num );
Copies the first num characters of source to destination. If the end
of the source C string (which is signaled by a null-character) is
found before num characters have been copied, destination is padded
with zeros until a total of num characters have been written to it.
By calling strncpy(myString, "Over", 5), you are actually copying "Over\n" into myString. You are probably better off calling strncpy with the last parameter as strlen(source).
Try the following
#include <iostream>
#include <string.h>
using namespace std;
int main() {
char myString[] = "Hello There";
printf("%s\n", myString);
strncpy(myString, "Over", 4); // I want this to print out "Over There"
strcpy( myString + 4, myString + 5 );
cout<< myString<<endl; // this prints out ONLY as "Over"
for (int i = 0; i <10; i++){
cout<< myString[i];
}// I wanted to see what's going on this prints out as Over? There
// the ? is upside down, it got added in
cout<< endl;
return 0;
}

Program stop working by strcat() with pointer

I have a problem, do not to compile this code but, to execute this program. When I run it in the terminal it prints the first 2 cout then the program stops working and the screen on the windows that tells you, i think the problem is to strcat.
I'm using DEVC++ and I have windows 7 pro.
#include <iostream>
#include <string>
#include <cstdlib>
#include <string.h>
using namespace std;
int main() {
char* cambia[] = {"ciao "};
char* c[] = {"mondo"};
cout << "*c: " << *c << endl;
cout << "*cambia: " << *cambia << endl;
strcat( *cambia, *c );
cout << "*cambia: " << *cambia << endl;
}
You don't use strcat() in C++ if you don't absolutely have to (e.g. when maintaining legacy code and touching as little stuff as possible).
Use std::string and its member functions like find or substr for simple tasks, string streams or Boost libraries for more complex string splitting.
At any rate, stay away from strcat().
The method strcat() adds the string from the second argument to the buffer of which you submit to the first argument.
First, the buffer has to be writable. In your example, you are passing a string literal as buffer. Naturally, string literals are read-only. But even then, the string literal has no spare space where the new string could be added.
Instead of fixing your code, let me show you some proper examples how to concat strings in C++ and in C.
This example is showing you how to concat two C++ strings:
#include <iostream>
#include <string>
int main(int argc, const char * argv[])
{
// Create a new C++ string with an initial text.
std::string result = "First string part ";
std::cout << "Result: " << result << std::endl;
// Add some text
std::string textToAppend = "and the second part";
result.append(textToAppend);
std::cout << "Result: " << result << std::endl;
return 0;
}
The following example is showing you how to concat two strings in C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, const char * argv[])
{
// The two texts to concat
const char *firstText = "This is the first text ";
const char *secondText = "and this is the second one";
// A buffer which is large enough for the operation.
const int bufferSize = 1024;
char buffer[bufferSize];
// Copy the initial text into the buffer.
strncpy(buffer, firstText, bufferSize);
// Add the secon string
strncat(buffer, secondText, bufferSize-strlen(buffer));
// Output the string
printf("Result: %s\n", buffer);
return 0;
}
I suggest, you should use C++ strings if possible. They automatically manage the memory which prevent many memory related issues with C strings.
This line
char* cambia[] = {"ciao "};
creates a variable named cambia in a dynamically created part of memory, called 'stack'. The variable is an array with no declared size, and elements of that array are pointers to characters.
The size of the array follows from the initializer
{"ciao "}
which implies the array will have only one element, and that element is initialized with a value pointing at the first character of string "ciao ". However, the string "ciao " is placed in some completely different area of memory - it is in static block, initialized by a compiler with values found in the program's code. Compiler does not know how you use these values, in particular it doesn't know you will extend it with strcat, so it will not reserve any additional space after the string.
As a result when you concatenate "mondo" to "ciao ", you overwrite some data in memory, possibly some important data...
I'd suggest you to declare local variables for your string, with explicit size:
char cambia[ 20] = "ciao ";
char c[] = "mondo";
This will make a cambia variable long enough to keep 19-character string (plus implicit terminating zero byte '\0', ASCII NUL) and initialize its first 6 bytes with letters 'c', 'i', 'a', 'o', a space ' ' and NUL. Variable c is implicitly sized to 6 (the initializing string length 5 plus 1 for terminating NUL).
Then you can safely concatenate
strcat( cambia, c);
to obtain 11-character string "ciao mondo" and print it out
cout <<"cambia: "<<cambia<<endl;
The problem here is that you are trying to write to a read-only string storage.
These declarations:
char* cambia[] = {"ciao "};
char* c[] = {"mondo"};
declare two arrays, each with a constant string member. The "ciao " and "mondo" are located in read-only memory.
So when you call strcat(*cambia, *c), you are trying to write "mondo" onto the end of "ciao ". Not only does this write to read-only memory, but it also writes outside the memory space given for the string - there is only space for 6 char in the "ciao " string, and you are trying to add another 5 to the end of that.
The solution is to reserve some space for each string. There are various ways to do this. Here's a simple one:
char acambia[20] = "ciao "; // Space for 20 characters.
char* cambia[] = { acambia };
Of coruse, not using the extra level of indirection would make it simpler:
char cambia[20] = "ciao ";
char c[] = "mondo";
strcat(cambia, c);
would achieve the correct result.
First of all you need not headers
#include <string>
#include <cstdlib>
because neither declaration from them is used.
Aslo header
#include <string.h>
should be substituted for
#include <cstring>
In these statements
char* cambia[] = {"ciao "};
char* c[] = {"mondo"};
you defined two arrays each of them having one element of type const char *. The compiler should issue either an error or a warning because these definitions are not correct. It would be correctly to define the arrays the following way
const char* cambia[] = {"ciao "};
const char* c[] = {"mondo"};
These two statements define arrays of const pointers to string literals. It is undefined behaviour if there ia an attempt to change a string literal in a program. Programs are allowed to place string literals in a read-only memory.
You are right saying that the main problem is in statement
strcat( *cambia, *c );
Function strcat appends one character array to the end of another character array. So the second cjaracter array must reserve enough memory that accomodates the appended character array. If you even would define correctly array cambia as
char cambia[] = {"ciao "};
it had no enough memory to store also characters of array c.
So before using strcat you need to reserve enough memory where the concatenated result array would be placed.
You could do this for example the following way
char s[11];
strcpy( s, *cambia );
strcat( s, c );
cout << "s: " << s << endl;
Take into account that instead of character arrays you could use objects of standard class std::string
In this case to append one string to another is made very simply. For example
std::string cambia = "ciao ";
std::string c = "mondo";
cambia += c;
Or
cambia.append( c );

How to terminate a std::string in C++?

I'm trying to remove all punctuation characters from a std::string in C++. My current code:
string str_in;
string::size_type i, j;
cout << "please input string with punctuation character..." << endl;
cin >> str_in;
for (i = 0, j = 0; i != str_in.size(); ++i)
if (!ispunct(str_in[i]))
str_in[j++] = str_in[i];
str_in[j] = '\0';
cout << str_in << endl;
Is str_in[j] = '\0'; wrong?
If you want to truncate str_in to the first j characters, you can say str_in.resize(j).
If you want to use the standard library you could apply the erase-remove idiom like this:
#include <algorithm>
#include <iostream>
#include <string>
int main()
{
std::string str_in;
std::getline(std::cin, str_in);
// Here is where the magic happens...
str_in.erase(std::remove_if(str_in.begin(), str_in.end(), ::ispunct), str_in.end());
std::cout << str_in << '\n';
return 0;
}
the C++ string type is NOT implemented to be null terminated (although a c_str() call will give you a null terminated string.)
So yes, str_in[j] = '\0' is wrong for at least two reasons:
The str_in.length() will not reflect the size of the string you expect with the punctuation removed.
The null charatcter is an extra charter which will be sent to any output stream,such as cout << str_in;
Using the std::string class you should probably not oveeride the same buffer, but probably use a str_out buffer instead which will have the right length after you copy all the wanted (i.e. excluding the punctuation character), OR you should instead adjust the length of the str_in instead of adding the null.
I think str_in[j] = '\0' is wrong when the string has no any punctuation.
Instead of modifying the same string, create a new string (e.g. str_out) and append to that:
str_out += str_in[i];

converting integer to string C++

I am trying to convert an integer to char array and I came across this piece of code
int i = 5;
std::string s;
std::stringstream out;
out << i;
s = out.str();
But when I try to print the value of s it still prints 5. I don't know if its supposed to do that or am I doing something wrong? Besides I would prefer if I could convert the same int to char array. But I would appreciate any help in the matter.
Thanks!
Code taken from: Alternative to itoa() for converting integer to string C++?
Yes, it's supposed to do that. You'd (primarily) notice the difference from just printing a number out directly if you do some other string-type manipulation on the result (e.g., concatenating it with other strings, searching for characters in the string).
Just for example:
std::cout << i+i; // should print "10"
std::cout << s+s; // should print "55"
Besides I would prefer if I could convert the same int to char array.
char *charPtr = new char[ s.length() + 1 ] ; // s is the string in the snippet posted
strcpy( charPtr, s.c_str() ) ;
// .......
delete[] charPtr ; // Should do this, else memory leak.
If you would like to stop worrying about issues like that you might be interested in boost/lexical_cast.hpp.
#include <boost/lexical_cast.hpp>
#include <string>
#include <iostream>
int main() {
const int i=5;
const char* s = boost::lexical_cast<std::string>(i).c_str();
std::cout << s << std::endl;
}