I have problem in my split Sentence function .
The idea of my function split any Sentence and add it to array like
Example:
Sentence:: Hello world.
My function will works:: (array[0]= hello, array[1]= world).
This is my code
void splitSentence(char *Sentence, char symb){
const int Size = strlen(Sentence);
string SentenceResult[2];
int count= 0;
stringstream stream;
for(int i=0;i<Size;i++){
stream << Sentence[i];
if((Sentence[i] == symb) || (Sentence[i] == '\0')){
SentenceResult[count] = stream.str();
count++;
stream.str(" ");
}
}
cout << "Stream: " << stream.str() << endl;
cout << "Word [0]: " << SentenceResult[0] << endl;
cout << "Word [1]: " << SentenceResult[1] << endl;
}
The result
Stream: world
array [0]: hello
array [1]: // empty (must be "world")
What the problem in my function.
Why array[1] is empty .
const int Size = strlen(Sentence);
This calculates the length of the string data, but not the final null terminator, so your loop will not find the terminator, and won't include the last word. You want to add one to this value to get the full length of the terminated string.
Your for loop does not run far enough to get to the Sentence[i] == '\0' case. It will only run up to the "d" of "hello world", so the conent of the stream is not written anymore into the output array.
You could for example write:
const int Size = strlen(Sentence)+1;
and you have included the final null byte.
You just need to change your for loop:
for(int i=0; i <= Size; i++)
Related
I'm trying to invert the case of some strings, and I did it, but I have some extra characters in my return, is it a memory problem? Or because of the length?
char* invertirCase(char* str){
int size = 0;
char* iterator = str;
while (*iterator != '\0') {
size++;
iterator++;
}
char* retorno = new char[size];
for (int i = 0; i < size; i++) {
//if capital letter:
if (str[i] < 96 && str[i] > 64) {
retorno[i] = str[i] + 32;
}
// if lower case:
else if (str[i] > 96 && str[i] < 123) {
retorno[i] = str[i] - 32;
}
//if its not a letter
else {
retorno[i] = str[i];
}
}
return retorno;
}
For example, if I try to use this function with the value "Write in C" it should return "wRITE IN c", but instead it returns "wRITE IN cýýýýÝݱ7ŽÓÝ" and I don't understand where those extra characters are coming from.
PS: I know I could use a length function, but this is from school, so I can't do that in this case.
add +1 to the size of the char array.
char* retorno = new char[size+1];
add a null-terminated string before returning retorno.
retorno[size] = '\0';
Your output string is not null-terminated
When you iterate through the input string, you increment size until you reach null. That means the null is not copied to the output string. After you exit the loop, you should increment size once more to capture the end.
As an aside, it's probably a good idea to constrain size to some maximum (while(*iterator != '\0' && size < MAXSIZE)) in case someone passes a non-terminated string into your function. If you hit the max size condition, you'd need to explicitly add the null at the end of your output.
Your string should be null terminated; which is what you are looking for when you get the initial size of the string. When you create the new string, you should allocated size+1 chars of space, then retorno[size] should be set to a null terminating character (i.e. '\0'). When you attempt to print a char* using printf or cout (or similar mechanisms), it will keep printing characters until it find the null terminating character, which is why you are getting the garbage values after your expected output.
On another note, c++ has helpful functions like std::islower / std::isupper and std::tolower / std::toupper
From what I can tell, there could be 2 things going on here:
Like everyone here mentioned, the absence of a null terminating character ('\0') at the end of your char array could be causing this.
It could be the way you are printing results of your retorno character string outside of your invertirCase() function.
I tested out your function in C++14, C++17 and C++20 and it returned the correct result each time, both with the null terminating character at the end of the retorno char array and without it.
Try printing your result inside of your function before returning it, to identify if this is being caused inside of your function or outside of it. Like so:
char* invertirCase(char* str){
// [... truncated code here]
for (int i = 0; i < size; i++) {
// [... truncated code here]
}
cout << " **** TESTING INSIDE FUNCTION ****" << endl;
cout << "-- Testing index iteration" << endl;
for (int i = 0; i < size; i++) {
cout << retorno[i];
}
cout << endl;
cout << "-- Testing iterator iteration" << endl;
for (char* iterator = retorno; *iterator != '\0'; iterator++) {
cout << *iterator;
}
cout << endl;
cout << "-- Testing advanced for loop" << endl;
for (char character : retorno) {
cout << character;
}
cout << " **** END TESTING ****" << endl;
cout << endl;
return retorno;
}
This way you could possibly identify both if the problem occurs inside of your function or if the problem is occurring because of the way you may be printing your result as well.
Okay. I have taken a sentence and split into an array thus far with this code I found online:
string strWords[5];
short counter = 0;
for(short i =0; i<texttoChange.length();i++)
{
strWords[counter] +=texttoChange[i];
if(texttoChange[i] == ' ')
{
counter++;
}
}
for(short i=0;i<5;i++)
{
cout << strWords[i] << "(" << strWords[i].size() << ")" << endl;
}
Now I want to take strWords[i] and split that array into an array of characters or single letter string array. Is it Possible?
Assuming you need a c style array, you can do,
char *charArray = strWords[i].c_str();, you can get the size by strlen(charArray)
otherwise there is no point of converting string to char array.
In the following code the length of the reversed string is being returned as zero which should not be the case:
int main() {
string for_reversal;
string reversed;
int i,j,length, r_length;
cout << "Enter the string : \n";
cin >> for_reversal;
cout << "Entered string is : " << for_reversal <<"\n";
cout << "String length is : " << for_reversal.length() << "\n";
length = for_reversal.length();
for (i=0; i<=length; i++)
{
reversed[i] = for_reversal[length - i-1];
cout << for_reversal[length-i] << "\t";
}
reversed[length+1]='\0';
cout << "\n";
r_length = reversed.length();
cout << "Reversed String length is : " << r_length << "\n";
cout << "Reversed String is : " << reversed;
return 0;
}
Not sure whats going wrong here.
There are length valid characters in a string with length length. In your cycle you access the element with index length which is out of bounds for the string and this invokes undefined behavior.
Additionally you can not assign values to cells in a string that are outside of its current size, while you assign values to the cells in reversed before resizing the string appropriately. This leads to second undefined behavior.
Having in mind the two issues I mentioned above the behavior of your problem is really not defined. However the output does makes sense if we ignore that - you assign to reversed[0] the value of for_reversal[length], which is probably '\0'. As a result the length of reversed is now 0.
Change
reversed[i] = for_reversal[length - i-1];
to
reversed+=for_reversal[length - i-1];
The way you're doing it is accessing the string out of its bound, paving the way for all kinds of hell breaking through. They way proposed above will append stuff to the string, reserving space as needed.
You could try and reserve space in "reversed" (http://www.cplusplus.com/reference/string/string/reserve/) so it can hold the original string (reversed.reserve(for_reversal.size())).
In any case, please not that you're not reserving space for the \0 character. Either reserve a bigger string or append \0 with the + operator.
The problem is here:
for (i = 0; i <= length; i++) {
reversed[i] = for_reversal[length - i-1];
// ...
}
With the statement:
reversed[i]
You're actually trying to access the i-th element of the string, with i=0, 1, ..., length.
But at that moment, the object string reversed is an empty string. Indeed you've created it with:
string reversed;
That is default constructor which initializes an empty string.
In other words, reversed[i] access to undefined memory location, since reversed is void, and there is no i-th position in the string.
Solution
In order to reverse a string you may find this code useful:
std::string reversed;
for(auto rit = for_reversal.rbegin(); rit != for_reversal.rend(); ++rit) {
reversed.push_back(*rit);
}
This code should be safer that your, using iterators (in that case reversed iterator).
Note
Moreover there is no need to append the '\0' char at the end, because the class string already handles that.
The program has undefined behavior because the string reversed is empty
string reversed;
and you may not use the subscript operator
reversed[i] = for_reversal[length - i-1];
^^^^^^^^^^^
to assign values to the string.
Also there is no need to append the zero character to objects of type std::string.
Take into account that in the loop
for (i=0; i<=length; i++)
{
reversed[i] = for_reversal[length - i-1];
cout << for_reversal[length-i] << "\t";
}
then i is equal to length then you will have
reversed[length] = for_reversal[-1];
^^^^^
The simplest way to create a reversed string is the following
#include <iostream>
#include <string>
int main()
{
std::string for_reversal;
std::cout << "Enter the string: ";
std::cin >> for_reversal;
std::string reversed( for_reversal.rbegin(), for_reversal.rend() );
std::cout << "\nReversed String length is : " << reversed.length() << "\n";
std::cout << "Reversed String is : " << reversed << std::endl;
return 0;
}
The program output is
Enter the string: Hello
Reversed String length is : 5
Reversed String is : olleH
If you want to write the loop yourself then you should reserve enough memory in the reversed string or at least use member function push_back instead of the subscript operator if the string initially is empty. The program can look for example the following way
#include <iostream>
#include <string>
int main()
{
std::string for_reversal;
std::string reversed;
std::cout << "Enter the string: ";
std::cin >> for_reversal;
reversed.reserve( for_reversal.length() );
for ( std::string::size_type i = for_reversal.length(); i != 0; i-- )
{
reversed += for_reversal[i-1];
}
std::cout << "\nReversed String length is : " << reversed.length() << "\n";
std::cout << "Reversed String is : " << reversed << std::endl;
return 0;
}
The program output will be the same as shown above
Enter the string: Hello
Reversed String length is : 5
Reversed String is : olleH
first initialize string reversed with empty string i.e string reversed="";
after this change for loop:
for(int i=0;i<length;i++)
{
reversed+=for_reversal[length-1-i];
cout << for_reversal[length-i] << endl;
}
int r_length=reversed.length();
cout << "reversed string length : " << r_length << endl;
cout << "Reversed string is : " << reversed << endl;
hope u understand.
I'm a beginning student of C++ and i encountered a problem with the following code:
I'm trying to concatenate a 'new line' or "\n" to a string in a matrix of char.
So far I managed to concatenate a " " char but the char "\n" or just typing multiple " " won't work.
The actual sample is getting 3 strings in const value of 10 (max chars) for each of the 3 matrix's I defined-assigning values to the first two and using a function to 'change' the third and printing it.
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
const int LINES = 3;
const int MAXCHARS = 10; //TO DO: change to 81 for final version
void cpyAndCat(char[][MAXCHARS], char[][MAXCHARS], char[][MAXCHARS], int);
void main()
{
char text1[LINES][MAXCHARS], text2[LINES][MAXCHARS], text3[LINES][MAXCHARS];
cout << "Enter " << LINES << " lines into text1:\n";
for (int i = 0; i < LINES; i++) // assign the matrix of chars text1 with strings
{
_flushall();
cin.getline(text1[i], MAXCHARS);
}
cout << "Enter " << LINES << " lines into text2: \n";
for (int i = 0; i < LINES; i++) // assign the matrix of chars text2 with strings
{
_flushall();
cin.getline(text2[i], MAXCHARS);
}
//TO DO: call the function which will recieve text1 and text2
//and put blank line(line too long) or copied line from text1 and catanted line form text2.(long correct size)
cpyAndCat(text1, text2, text3, LINES);
cout << "============================================================\n";
for (int i = 0; i < LINES; i++) // print third matrix of chars, prints 3 lines of either text or '\n'
{
_flushall();
cout << text3[i];
cout << endl;
}
system("pause");
}
void cpyAndCat(char text1[][MAXCHARS], char text2[][MAXCHARS], char text3[][MAXCHARS], int lines)
{
for (int i = 0; i < lines; i++) // searches if length of string from first 2 matrix is valid
{
if (strlen(text1[i]) + strlen(text2[i]) < MAXCHARS) // if so, copy the first to the third and catanate the second to the third
{
strcpy_s(text3[i], text1[i]);
strcat_s(text3[i], text2[i]);
}
else // if else (: , catanate 'new line' to the third matrix
{
strcat_s(text3[i], "\n"); // not working
}
cout << endl;
}
}
strcat_s and strcpy_s need three parameters, not two. I'm suprised you have anything compiling at all.
Also, you strcat onto text3 without ever initializing it. So that's probably undefined behaviour...
strcat_s takes 3 arguments, you are missing the size in bytes, also, the string was never initialized.
You would want to copy into the string and afterwards, if needed, concatenate.
Don't forget to take into account the '\0' at the end of every string.
strcpy_s(text3[i], 2, "\n");
I'm just starting out programming but I've had a lot of ideas about how to make my life easier when parsing files by making a program that maps addresses of data when read into memory from a file.
Note: I cut down the wall text here's the problem in a nutshell
How does one parse an array of chars with no null terminator but the words all begin with uppercase letters so Capital can be used as delimiter?
Basically I want to parse text file that is just 'WordWordWord' and send each word to a to it's own separate string variable then be able to write each word to a text file with a newline added.
I wanted to do some more advanced stuff but I was asked to cut the wall of text so that will do for now :)
//pointers and other values like file opening were declared
int len = (int) strlen( words2 );
cout << "\nSize of Words2 is : " << len << " bytes\n";
// Loops through array if uppercase then...
for (int i = 0; i < len; i++)
{
if (isupper(words2[i]))
{
// Output the contents of words2
cout << "\n Words2 is upper : " << words2[i] << "\n";
b1 = &words2[i];
//output the address of b1 and the intvalue of words2[var]
cout << "\nChar address is " << &b1 << " word address is " << (int) words2[i] << "\n";
cout << "\nChar string is " << b1 << " address +1 "<< &b1+1 <<"\n and string is " << b1+1 << "\n";
}
cout << "\nItem I is : i " << i << " and words2 is " << words2[i] << "\n";
}
fin.clear();
fin.close();
fout.close();
Easy. Use Boost.Tokenizer, with char_separator("", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"). "" is the set of dropped separators, and A-Z is the set of kept separators. (If you'd used A-Z as dropped separators, you'd get ord ord ord because you'd drop the W.)
Since you also
wanted to do some more advanced stuff
I would have a look a Boost.Regex from the get go. This is a good library for doing textual manipulations.
vector<char *> parsedStrings;
char * words = "HelloHelloHello";
int stringStartAddress = 0;
for (int i = 0; i <= strlen(words); i++)
{
/* Parses word if current char is uppercase or
if it's the last char and an uppercase char was previously matched */
if (isupper(words[i]) || ((i == strlen(words)) && (stringStartAddress != 0)))
{
// Current char is first uppercase char matched, so don't parse word
if (stringStartAddress == 0)
{
stringStartAddress = ((int)(words + i));
continue;
}
int newStringLength = ((int)(words + i)) - stringStartAddress;
char * newString = new char[newStringLength + 1];
// Copy each char from previous uppercase char up to current char
for (int j = 0; j < newStringLength; j++)
{
// Cast integer address of char to a char pointer and then get the char by dereferencing the pointer
// Increment address to that of the next char
newString[j] = *((char *)stringStartAddress++);
}
newString[newStringLength] = '\0'; // add null-terminator to string
parsedStrings.push_back(newString);
}
}