I am working a code that will find the amount of duplicated words from a imported file.
The input stream represents a file containing a series of lines. The function should
examine each line looking for consecutive occurrences of the same token on the same line and
print each duplicated token along how many times it appears consecutively. Non-repeated
tokens are not printed.
Here is what I have:
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
using namespace std;
int main()
{
ifstream in("file.txt");
if (! in)
{
cerr << "Could not open file.txt.";
return EXIT_FAILURE;
}
string str;
int count = 0;
int len=str.length();
while(getline(in,str)){
for(int i = 0; i < len; i++){
if(str.at(i) == str.at(i+1)){
count++;
}
else if(str.at(i) != str.at(i+1)){
i++;
}
}
cout << str << "*" << count << endl;
}
}
The .txt contains:
hello how how are you you you you
I I I am Jack's Jack's smirking smirking smirking smirking smirking revenge
bow wow wow yippee yippee yo yippee yippee yay yay yay
one fish two fish red fish blue fish
It's the Muppet Show, wakka wakka wakka
The output should be:
how*2 you*4
I*3 Jack's*2 smirking*5
wow*2 yippee*2 yippee*2 yay*3
wakka*3
a=list('this is my laptop')
b=list(set(a))
for i in b:
if i==' ':
continue
c=a.count(i)
if c>1:
print('{} is {}'.format(i,c))
#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
using namespace std;
int main()
{
ifstream in("file.txt");
if(!in){
cerr << "Could not open file.txt.";
return EXIT_FAILURE;
}
string str;
string str2;
string n;
string tab[100];
string tab3[100];
unsigned int tab2[100];
unsigned int tab4[100];
unsigned int i = 0;
unsigned int k = 0;
unsigned int l = 0;
unsigned int tablenght;
unsigned int tablenght2;
k = 0;
//it reads every line of text in file str2
while(getline(in,str2)){
//it add every line of text str2 to str so you get whole file text
str += str2;
str += ' ';
//you need to add a character to mark where was the new line
str += "0 ";
}
for(i = 0; i < str.length(); i++){
/*you check every single character in string str if that char is not
space than it writes it to string table tab, if that char is space than it
adds one to your index so it will write down the next word in next
index of table tab*/
if(str[i] != ' '){
tab[k] += str[i];
}else{
k++;
//that is for two spaces
if(str[i+1] == ' '){
k--;
}
}
}
//k+1 is actually how many words and indexes you wrote to table tab
tablenght = k+1;
l = 0;
k = 0;
for(i = 0; i < tablenght; i++){
//you need to reset the number of repeats k to zero if you go to another line
if(tab[i] == "0"){
k = 0;
}
//there you get the number k how many times does some word repeats itself
if(tab[i] == tab[i+1]){
k++;
//you need to reset k if tab current is not equal to tab next
}else{
k = 0;
}
//there you store k values into integer table tab2
tab2[l] = k+1;
l++;
}
l = 0;
/*there you need to check if current string of table tab is equal to next string
in table tab and if it is you need to set next string to tab3[l] if you dont do
that you get something like that you*4 you*4 you*4 you*4 instead of only you*4*/
for(i = 0; i < tablenght-1; i++){
if(tab[i] == tab[i+1]){
tab3[l] = tab[i+1];
tab4[l] = tab2[i];
}else{
l++;
}
if(tab[i+1] == "0"){
tab3[l] = tab[i+1];
}
k++;
}
tablenght2 = l;
//there you cout both tables
for(i = 0; i < tablenght2; i++){
/*you need to check if number is bigger than 1 because it need to cout only
the words that repeats itself for more than one time than you need to check
that table tab3 doesnt contain string with zero that we previously added
that we could check later if it needs to go in another line and we
need to check that tab3 index is not empty*/
if(tab4[i] > 1 && tab3[i] != "0" && !tab3[i].empty()){
cout << tab3[i] << "*" << tab4[i] << " ";
}
/*thats the zero that we wrote to table in the begining and that we can now
write a new line*/
if(tab3[i] == "0"){
cout << endl;
}
}
return 0;
}
Related
I am trying to encrypt a message by having it print in 3 columns and as many rows as needed. I also need help with reversing my encryption
I am having most difficulties printing my results. I am working with a Rail Fence Cipher key N which dictate number of columns. N = Number of Columns, but in my code I made it default = 3.
My Conditions are
.The plaintext is written, the sequence of each letter’s vertical position on the columns varies right and left in a repeating cycle
.The ciphertext is then read off in columns
int main()
{
int num_cols, num_spaces=0 ,f=0;
string message;
// accept the message from the user
cout<<" Enter the message to encrypt : ";
getline(cin,message);
num_cols=3;
// first we need to remove any spaces that might be there in the message
for(int i = 0 ; i<message.size(); ++i)
{
if(message[i] == ' ')
{
++num_spaces;
}
}
remove(message.begin(), message.end(),' ');
message.resize(message.size() - num_spaces);
cout<<"\n The equivalent cipher text would be : "<<endl;
vector<vector<char>> matrix(3,vector<char>(message.size(),' '));
// encrypt the message
for(int i=0,j=0; i<message.size(); i++)
{
matrix[j][i] = message[i];
if(j == 3-1)
{
f=1;
}
else if(j==0)
f=0;
if(f==0)
{
j++;
}
else j--;
}
// Printing the grid
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < message.size(); j++)
{
cout << matrix[i][j];
}
cout << endl;
}
return 0;
// end
}
So, your first problem, the correct output is easy to solve. You had just a minor typo. The encrypted text will be printed with:
// Printing the grid
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < matrix[i].size(); j++)
{
if (matrix[i][j] != ' ')
std::cout << matrix[i][j];
}
}
If you want to see the rails, then please use:
std::cout << "\n\n";
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < matrix[i].size(); j++)
{
std::cout << matrix[i][j];
}
std::cout << '\n';
}
So, with that the question is answered.
Deciphering is similar simple.
You create again rails and do for the length of the string the same as before. But, do not put a letter in that position, but a marker, for example a '*'.
Then go rail by rail (row by row) through your rails, and everytime, when you find a marker, the replace that marker with the next character from the encrypted text.
Then go again zigzag through your rails, and collect all characters at the corresponding positions. The result will be the drcrypted text.
I prepared a complete solution for encryption and decryption. The number of rails can be specified at the top. In my example I use 5. Please change it to 3, if you want. I made it straigthforward. For easier understanding. The code should be further optimized. E.g., there are a lot of repetions that could be put into functions.
Anyway. It is just an example:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
// Please specify the number of rails:
constexpr size_t NumberOfRails = 5u;
constexpr char EmptyRailPosition = '.';
constexpr char UsedRailPosition = '*';
// Some aliases for easier writing and understanding
using Rail = std::vector<char>;
using Rails = std::vector<Rail>;
std::string clearText{ "abcd efgh ijkl mnopqrst uv wxyz" };
int main() {
// Remove all spaces from string
clearText.erase(std::remove_if(clearText.begin(), clearText.end(), ::isspace), clearText.end());
// Create the rails for the encryption
Rails encryptedRails(NumberOfRails, Rail(clearText.length(), EmptyRailPosition));
// Now encrypt
int railIndexIncrementor{ -1 };
size_t railIndex{};
// Go thorugh all characters in the clear string
for (size_t columnIndexInClearText{}; columnIndexInClearText < clearText.length(); ++columnIndexInClearText) {
// Write character on rail
encryptedRails[railIndex][columnIndexInClearText] = clearText[columnIndexInClearText];
// If we are at the top or at the bottom of our rails, then change direction
if (0 == (columnIndexInClearText % (NumberOfRails-1)))
railIndexIncrementor = -railIndexIncrementor;
// Modify rail index. Increment or decrement. Depending on railIncrementor
railIndex = static_cast<int>(railIndex) + railIndexIncrementor;
}
// Here we will store the encrypted message
std::string encryptedMessage{};
// Show rails
std::cout << "\nRails: \n\n";
for (const Rail& rail : encryptedRails) {
for (const char c : rail) {
std::cout << c;
// Build string with encrypted message
if (c != EmptyRailPosition) encryptedMessage += c;
}
std::cout << '\n';
}
// Show encrypted message
std::cout << "\n\nEncrypted message: \n\n" << encryptedMessage << "\n\n";
// ------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------
// Decryption
// ------------------------------------------------------------------------------------
// Build empty rails
Rails decryptedRails(NumberOfRails, Rail(clearText.length(), '.'));
railIndexIncrementor = -1;
railIndex = 0;
// Go through all necessary positions in the decryption rails
for (size_t columnIndexInEncryptedText{}; columnIndexInEncryptedText < encryptedMessage.length(); ++columnIndexInEncryptedText) {
// Write makrker on rail
decryptedRails[railIndex][columnIndexInEncryptedText] = UsedRailPosition;
// If we are at the top or at the bottom of our rails, then change direction
if (0 == (columnIndexInEncryptedText % (NumberOfRails - 1)))
railIndexIncrementor = -railIndexIncrementor;
// Modify rail index. Increment or decrement. Depending on railIncrementor
railIndex = static_cast<int>(railIndex) + railIndexIncrementor;
}
// Show rails with markers
std::cout << "\n\nRails with markers: \n\n";
for (const Rail& rail : decryptedRails) {
for (const char c : rail) std::cout << c;
std::cout << '\n';
}
// Now exchange the markers with the characters of the encrypted string
size_t indexInEncryptedMessage{};
// Now, put a character from the string at positions with marker
for (Rail& rail : decryptedRails)
for (char& c : rail)
if (c == UsedRailPosition) c = encryptedMessage[indexInEncryptedMessage++];
// Show rails with replaced markers
std::cout << "\nRails with replaced markers, so decrypted rails:\n\n";
for (const Rail& rail : encryptedRails) {
for (const char c : rail) std::cout << c;
std::cout << '\n';
}
// Read back string from rails
railIndexIncrementor = -1;
railIndex = 0;
std::string decrytpedMessage{};
// Go through all necessary positions in the decryption rails
for (size_t columnIndexInEncryptedText{}; columnIndexInEncryptedText < encryptedMessage.length(); ++columnIndexInEncryptedText) {
// Read character from rail
decrytpedMessage += decryptedRails[railIndex][columnIndexInEncryptedText];
// If we are at the top or at the bottom of our rails, then change direction
if (0 == (columnIndexInEncryptedText % (NumberOfRails - 1)))
railIndexIncrementor = -railIndexIncrementor;
// Modify rail index. Increment or decrement. Depending on railIncrementor
railIndex = static_cast<int>(railIndex) + railIndexIncrementor;
}
// and, show decrypted message
std::cout << "\n\nDecypted message:\n\n" << decrytpedMessage << "\n\n";
return 0;
}
*Sorry about my poor English. If there is anything that you don't understand, please tell me so that I can give you more information that 'make sence'.
**This is first time asking question in Stackoverflow. I've searched some rules for asking questions correctly here, but there should be something I missed. I welcome all feedback.
I'm currently solving algorithm problems to improve my skill, and I'm struggling with one question for three days. This question is from https://algospot.com/judge/problem/read/RESTORE , but since this page is in KOREAN, I tried to translate it in English.
Question
If there are 'k' pieces of partial strings given, calculate shortest string that includes all partial strings.
All strings consist only lowercase alphabets.
If there are more than 1 result strings that satisfy all conditions with same length, choose any string.
Input
In the first line of input, number of test case 'C'(C<=50) is given.
For each test case, number of partial string 'k'(1<=k<=15) is given in the first line, and in next k lines partial strings are given.
Length of partial string is between 1 to 40.
Output
For each testcase, print shortest string that includes all partial strings.
Sample Input
3
3
geo
oji
jing
2
world
hello
3
abrac
cadabra
dabr
Sample Output
geojing
helloworld
cadabrac
And here is my code. My code seems to work perfect with Sample Inputs, and when I made test inputs for my own and tested, everything worked fine. But when I submit this code, they say my code is 'wrong'.
Please tell me what is wrong with my code. You don't need to tell me whole fixed code, I just need sample inputs that causes error with my code. Added code description to make my code easier to understand.
Code Description
Saved all input partial strings in vector 'stringParts'.
Saved current shortest string result in global variable 'answer'.
Used 'cache' array for memoization - to skip repeated function call.
Algorithm I designed to solve this problem is divided into two function -
restore() & eraseOverlapped().
restore() function calculates shortest string that includes all partial strings in 'stringParts'.
Result of resotre() is saved in 'answer'.
For restore(), there are three parameters - 'curString', 'selected' and 'last'.
'curString' stands for currently selected and overlapped string result.
'selected' stands for currently selected elements of 'stringParts'. Used bitmask to make my algorithm concise.
'last' stands for last selected element of 'stringParts' for making 'curString'.
eraseOverlapped() function does preprocessing - it deletes elements of 'stringParts' that can be completly included to other elements before executing restore().
#include <algorithm>
#include <iostream>
#include <vector>
#include <cstring>
#include <string>
#define MAX 15
using namespace std;
int k;
string answer; // save shortest result string
vector<string> stringParts;
bool cache[MAX + 1][(1 << MAX) + 1]; //[last selected string][set of selected strings in Bitmask]
void restore(string curString, int selected=0, int last=0) {
//base case 1
if (selected == (1 << k) - 1) {
if (answer.empty() || curString.length() < answer.length())
answer = curString;
return;
}
//base case 2 - memoization
bool& ret = cache[last][selected];
if (ret != false) return;
for (int next = 0; next < k; next++) {
string checkStr = stringParts[next];
if (selected & (1 << next)) continue;
if (curString.empty())
restore(checkStr, selected + (1 << next), next + 1);
else {
int check = false;
//count max overlapping area of two strings and overlap two strings.
for (int i = (checkStr.length() > curString.length() ? curString.length() : checkStr.length())
; i > 0; i--) {
if (curString.substr(curString.size()-i, i) == checkStr.substr(0, i)) {
restore(curString + checkStr.substr(i, checkStr.length()-i), selected + (1 << next), next + 1);
check = true;
break;
}
}
if (!check) { // if there aren't any overlapping area
restore(curString + checkStr, selected + (1 << next), next + 1);
}
}
}
ret = true;
}
//check if there are strings that can be completely included by other strings, and delete that string.
void eraseOverlapped() {
//arranging string vector in ascending order of string length
int vectorLen = stringParts.size();
for (int i = 0; i < vectorLen - 1; i++) {
for (int j = i + 1; j < vectorLen; j++) {
if (stringParts[i].length() < stringParts[j].length()) {
string temp = stringParts[i];
stringParts[i] = stringParts[j];
stringParts[j] = temp;
}
}
}
//deleting included strings
vector<string>::iterator iter;
for (int i = 0; i < vectorLen-1; i++) {
for (int j = i + 1; j < vectorLen; j++) {
if (stringParts[i].find(stringParts[j]) != string::npos) {
iter = stringParts.begin() + j;
stringParts.erase(iter);
j--;
vectorLen--;
}
}
}
}
int main(void) {
int C;
cin >> C; // testcase
for (int testCase = 0; testCase < C; testCase++) {
cin >> k; // number of partial strings
memset(cache, false, sizeof(cache)); // initializing cache to false
string inputStr;
for (int i = 0; i < k; i++) {
cin >> inputStr;
stringParts.push_back(inputStr);
}
eraseOverlapped();
k = stringParts.size();
restore("");
cout << answer << endl;
answer.clear();
stringParts.clear();
}
}
After determining which string-parts can be removed from the list since they are contained in other string-parts, one way to model this problem might be as the "taxicab ripoff problem" problem (or Max TSP), where each potential length reduction by overlap is given a positive weight. Considering that the input size in the question is very small, it seems likely that they expect a near brute-force solution, with possibly some heuristic and backtracking or other form of memoization.
Thanks Everyone who tried to help me solve this problem. I actually solved this problem with few changes on my previous algorithm. These are main changes.
In my previous algorithm I saved result of restore() in global variable 'answer' since restore() didn't return anything, but in new algorithm since restore() returns mid-process answer string I no longer need to use 'answer'.
Used string type cache instead of bool type cache. I found out using bool cache for memoization in this algorithm was useless.
Deleted 'curString' parameter from restore(). Since what we only need during recursive call is one previously selected partial string, 'last' can replace role of 'curString'.
CODE
#include <algorithm>
#include <iostream>
#include <vector>
#include <cstring>
#include <string>
#define MAX 15
using namespace std;
int k;
vector<string> stringParts;
string cache[MAX + 1][(1 << MAX) + 1];
string restore(int selected = 0, int last = -1) {
if (selected == (1 << k) - 1) {
return stringParts[last];
}
if (last == -1) {
string ret = "";
for (int next = 0; next < k; next++) {
string resultStr = restore(selected + (1 << next), next);
if (ret.empty() || ret.length() > resultStr.length())
ret = resultStr;
}
return ret;
}
string& ret = cache[last][selected];
if (!ret.empty()) {
cout << "cache used in [" << last << "][" << selected << "]" << endl;
return ret;
}
string curString = stringParts[last];
for (int next = 0; next < k; next++) {
if (selected & (1 << next)) continue;
string checkStr = restore(selected + (1 << next), next);
int check = false;
string resultStr;
for (int i = (checkStr.length() > curString.length() ? curString.length() : checkStr.length())
; i > 0; i--) {
if (curString.substr(curString.size() - i, i) == checkStr.substr(0, i)) {
resultStr = curString + checkStr.substr(i, checkStr.length() - i);
check = true;
break;
}
}
if (!check)
resultStr = curString + checkStr;
if (ret.empty() || ret.length() > resultStr.length())
ret = resultStr;
}
return ret;
}
void EraseOverlapped() {
int vectorLen = stringParts.size();
for (int i = 0; i < vectorLen - 1; i++) {
for (int j = i + 1; j < vectorLen; j++) {
if (stringParts[i].length() < stringParts[j].length()) {
string temp = stringParts[i];
stringParts[i] = stringParts[j];
stringParts[j] = temp;
}
}
}
vector<string>::iterator iter;
for (int i = 0; i < vectorLen - 1; i++) {
for (int j = i + 1; j < vectorLen; j++) {
if (stringParts[i].find(stringParts[j]) != string::npos) {
iter = stringParts.begin() + j;
stringParts.erase(iter);
j--;
vectorLen--;
}
}
}
}
int main(void) {
int C;
cin >> C;
for (int testCase = 0; testCase < C; testCase++) {
cin >> k;
for (int i = 0; i < MAX + 1; i++) {
for (int j = 0; j < (1 << MAX) + 1; j++)
cache[i][j] = "";
}
string inputStr;
for (int i = 0; i < k; i++) {
cin >> inputStr;
stringParts.push_back(inputStr);
}
EraseOverlapped();
k = stringParts.size();
string resultStr = restore();
cout << resultStr << endl;
stringParts.clear();
}
}
This algorithm is much slower than the 'ideal' algorithm that the book I'm studying suggests, but it was fast enough to pass this question's time limit.
The original prompt was:
Write a program that keeps track of a speakers bureau. The program should use a
structure to store the following data about a speaker:
Name
Telephone Number
Speaking Topic
Fee Required
The program should use an array of at least 10 structures. It should let the user enter
data into the array, change the contents of any element, and display all the data stored
in the array. The program should have a menu-driven user interface.
Input Validation: When the data for a new speaker is entered, be sure the user enters
data for all the fields. No negative amounts should be entered for a speaker s fee.
The added prompt was:
I need this to expand the search pattern with the potential one character of letter or digit typos. Only one character maybe a typo, in any position Try these test patterns should get the following results:
0-9 is 0x30-0x39
a-z is 0x41-0x5A
A-Z is 0x61-0x7A (or lower case it)
And I can't get the added prompt to work with my current program.
No other characters in the search pattern may be changed.
#include <iostream>
#include <cstring>
#include<string>
using namespace std;
bool print_one_typo(string input, string people[11], bool is_found[11])
{
bool found = false;
if (input[0] == '?')
{
char *strPtr = NULL;
for (int i = 0; i < 11; i++)
{
strPtr = strstr(people[i].c_str(), input.substr(1).c_str());
if (strPtr != NULL)
{
cout << "\t" << people[i] << endl;
found = true;
is_found[i] = true;
}
}
}
else
{
for (int i = 0; i < 11; i++)
{
bool match = true;
string str = people[i];
int value = str.find(input[0]);
for (int k = 0; k < input.length(); k++)
{
if (input[k] != '?' && input[k] != str[value++])
{
match = false;
break;
}
}
if (match && !is_found[i])
{
found = true;
cout << "\t" << people[i] << endl;
}
}
}
return found;
}
int main()
{
string people[11] = { "Becky Warren, 555-1223",
"Joe Looney, 555-0097",
"Geri Palmer, 555-8787",
"Lynn Presnell, 555-1225",
"Holly Gaddis, 555-8878",
"Sam Wiggins, 555-0998",
"Bob Kain, 555-8712",
"Tim Haynes, 555-7676",
"Warren Gaddis, 555-9037",
"Jean James, 555-9223",
"Ron Palmer, 555-7227" };
bool is_found[11] = { false };
string lookUp;
int i;
cout << "\t People and Phone numbers" << endl;
cout << "Enter name or phone number: ";
cin >> lookUp;
cout << "result: " << endl;
bool found = false;
bool output = false;
for (int i = 0; i < lookUp.length(); i++)
{
string local = lookUp;
found = print_one_typo(local.replace(i, 1, 1, '?'), people, is_found);
if (found) output = true;
}
if (!output)
cout << "No matching product was found" << endl;
return 0;
}
I think your code overthinks the problem. Also, you didn't specify if "typo" just means "wrong character", or a fuller range that includes dropped characters or inserted characters.
If you are only looking for matches with zero or one incorrect characters, but otherwise the same length, I think this code should do:
bool print_one_typo(string input, string people[11], bool is_found[11])
{
for (int i = 0; i < 11; i++)
{
if ( is_found[i] ) // Skip if it had already been found?
continue;
if ( input.length() != people[i].length() ) // Are they same length?
continue; // No: Skip it.
int typos = 0;
size_t len = input.length();
for (size_t j = 0; j != len && typos < 2; j++)
if ( input[j] != people[i][j] )
typos++;
if (typos < 2) // Fewer than 2 typos: We have a winner! Return it.
{
is_found[i] = true;
return true;
}
}
return false;
}
This code skips strings that differ in length, or which you're filtering out via the is_found[] array. Not sure why you're doing that, but I preserved that bit of your original code.
If it finds two strings that are the same length, it just compares them character by character, counting up typos. If it sees 2 or more typos, it skips to the next one. Otherwise, it takes the first string that's the same length but fewer than 2 typos.
I have a simple word wrap function that takes a long string as an input and then breaks that string into smaller strings and adds them to an array to be outputted later. Right now the last word or two isn't outputting. That's the main problem. However, I would also like to improve the function. I know it's kind of messy. I was wondering if there are any better ways of solving this problem. I think the array is unnecessary but I don't know how else to do it. After the array is filled with all the smaller strings, I just output them to a text file. Any suggestions would be greatly appreciated.
Here's the Word Wrap function:
void WordWrap(string inputString, string formatedAr[], const int SIZE)
{
unsigned int index;
unsigned int word;
unsigned int max = 65;
string outWord;
string outLine;
outWord = "";
outLine = "";
word = 0;
for(int i = 0; i < SIZE; i++)
{
formatedAr[i] = "";
}
for(index = 0; index <= inputString.length(); index++)
{
if(inputString[index] != ' ')
{
outWord += inputString[index];
}
else
{
if(outLine.length() + outWord.length() > max)
{
formatedAr[word] = outLine;
word++;
outLine.clear();
}
outLine += outWord + " ";
outWord.clear();
}
}
formatedAr[word] = outLine;
}
And this is where I call the function and output the array:
WordWrap(dvdPtr -> synopsis, formatedAr, SIZE);
index = 0;
while(index < SIZE && formatedAr[index] != "")
{
outFile << formatedAr[index] << endl;
index++;
}
Here is an example code.
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
void WordWrap(const string& inputString, vector<string>& outputString, unsigned int lineLength)
{
istringstream iss(inputString);
string line;
do
{
string word;
iss >> word;
if (line.length() + word.length() > lineLength)
{
outputString.push_back(line);
line.clear();
}
line += word + " ";
}while (iss);
if (!line.empty())
{
outputString.push_back(line);
}
}
/*
A simple test:
Input string: "aaa bbb ccccccc dddd d111111111111111 33333 4444444444 222222222 ajdkjklad 341343"
Length per line: 20
Output lines of strings:
Line 1: aaa bbb ccccccc dddd
Line 2: d111111111111111
Line 3: 33333 4444444444
Line 4: 222222222 ajdkjklad
*/
Hi there I'm reading a string and breaking each word and sorting it into name email and phone number. with the string joe bloggs joeblog#live.com 12345. But once i break everything down, the individual separated variables which hold the name,email and phone number have garbage characters at the end of them. I cant figure out why.
test file
//test file
#include <iostream>
#include <string>
#include "iofunc.h"
using namespace std;
int main(){
string str1 = "joe bloggs joeblog#live.com 12345";
iofunc func;
cout<<"|-----------------------getname DEMONSTRATION------------------|\n" << endl;
func.getName(str1);
cout<<"the names are: " << func.glob_name << endl;
cout<<"\n|-----------------------getphone DEMONSTRATION------------------|\n" << endl;
func.getPhone(str1);
cout<<"the phone number is:" << func.glob_phone << endl;
cout<<"\n|-----------------------getemail DEMONSTRATION------------------|\n" << endl;
func.getEmail(str1);
cout<<"the email address is:" << func.glob_email << endl;
return 0;
}
here's my get name function, the class is too big to scroll through:)
void iofunc::getName(string arg){
lineProcess(arg);
//make sure to call this depending on what function u are using
int name_count = 0;
int wspace_count = 0;
int arg_len = arg.length();
//int char_len = 0;
char name_temp[80];
name_count = numberofNames();
//line process was called before so this will work,
//make sure you call line process before using this function
//for special, condition when there is no space in front of names
if (special_condition == true){
int i = 0;
while(i < arg_len){
name_temp[i] = arg[i];
i++;
}
glob_name = string(name_temp);
}
if (special_condition == false){
if (name_count == 1){
int i = 0;
while (arg[i] != ' '){
name_temp[i] = arg[i];
i++;
}
glob_name = string(name_temp);
}
//for 2 names
if (name_count == 2){
for (int i = 0; i < arg_len;i++){
if (arg[i] == ' '){
wspace_count++;
}
if (wspace_count !=2){
name_temp[i] = arg[i];
}
}
glob_name = string(name_temp);
}
//for 3 names
if (name_count == 3){
for (int i = 0; i < arg_len;i++){
if (arg[i] == ' '){
wspace_count++;
}
if (wspace_count !=3){
name_temp[i] = arg[i];
}
}
glob_name = string(name_temp);
}
}
}
basic jist of all that is, im using the function called lineProcess to figure out whether there is an email, phone and name in the argument string, And the numberofNames functions gives how many names there are so that I can act accordingly.
I had to use char name_temp to copy just the names from string so that I can extract just that and assign it to the string variable named glob_name. It copies everything i need but it gives me that garbage after each extracted string.
any idea?.
EDITED
void iofunc::getName(string arg){
lineProcess(arg);
//make sure to call this depending on what function u are using
int name_count = 0;
int wspace_count = 0;
int arg_len = arg.length();
//int char_len = 0;
char name_temp[80];
int index_track = 0;
name_count = numberofNames();
//line process was called before so this will work,
//make sure you call line process before using this function
//for special, condition when there is no space in front of names
if (special_condition == true){
int i = 0;
while(i < arg_len){
name_temp[i] = arg[i];
index_track = i;
i++;
}
name_temp[index_track+1] = '\0';
glob_name = string(name_temp);
}
if (special_condition == false){
if (name_count == 1){
int i = 0;
while (arg[i] != ' '){
name_temp[i] = arg[i];
index_track = i;
i++;
}
name_temp[index_track+1] = '\0';
glob_name = string(name_temp);
}
//for 2 names
if (name_count == 2){
for (int i = 0; i < arg_len;i++){
if (arg[i] == ' '){
wspace_count++;
}
if (wspace_count !=2){
name_temp[i] = arg[i];
index_track = i;
}
}
name_temp[index_track+1] = '\0';
glob_name = string(name_temp);
}
//for 3 names
if (name_count == 3){
for (int i = 0; i < arg_len;i++){
if (arg[i] == ' '){
wspace_count++;
}
if (wspace_count !=3){
name_temp[i] = arg[i];
index_track = i;
}
}
name_temp[index_track+1] = '\0';
glob_name = string(name_temp);
}
}
}
When you do things like this:
while(i < arg_len){
name_temp[i] = arg[i];
i++;
}
You are copying the characters of the string to name_tmp, but not the 0 at the end which terminates the string.
add to each new string '\0' end-of string symbol
Garbage characters at the end of a string could indicate that you're not null-terminating the string (ending it with a 0x00 byte). This causes the string to continue reading until the next null character, which is actually past where the string's memory ends. This could even cause a segmentation fault in some cases.
You can fix this by adding '\0' to the end of each new string you create. Note that you will have to allocate a string one byte larger now, to hold that new ending character.
The others have pointed you in the right direction, you aren't appropriately terminating your c strings. Declaring a char array of length 80 just points to a block of memory, it doesn't initialise the array in any way, this means that unless you /0 terminate the string you copy into it, you'll get all the crap lying around on the end up to the 80 characters.
I've not written C++ in probably 15 years so the code below may not even work but hopefully it'll give you some ideas for a more elegant and maintainable solution.
void iofunc::getName(string arg){
lineProcess(arg);
//make sure to call this depending on what function u are using
int name_count = 0;
int wspace_count = 0;
int arg_len = arg.length();
//int char_len = 0;
string name_temp;
// Let's assemble a c-str version if the inbound arg string
char* cstr;
cstr = new char [arg.size()+1];
strcpy (cstr, arg.c_str());
name_count = numberofNames();
//line process was called before so this will work,
//make sure you call line process before using this function
//for special, condition when there is no space in front of names
if (special_condition == true){
glob_name = arg;
}
if (special_condition == false){
// Assuming there's at least 1 name, which we have to otherwise the original
// code may never set glob_name, let's use the C String function strtok
// to tokenise our newly created c string at each " ".
// Grab the first name.
name_temp = string(strtok(cstr, " "));
for (int i = 1; i < name_count; i++) {
// Grab names 2 to name_count as required and append them to name_temp
// We need to reinsert the space as strtok doesn't grab it.
name_temp += " " + string(strtok(NULL, " "));
}
// Assign our final name to glob_name
glob_name = name_temp;
}
}