Convert a string into a char array - c++

New to C++ and So here is part of a project I'm working on, taking a string and printing the most commonly used number along with how many times it was used. i thought this was right, but for some reason my char array wont be read in. any tips or suggestions on how to fix?
#include <string>
#include <iostream>
using namespace std;
char getMostFreqLetter(string ss);
int main() {
string s; //initilizing a variable for string s
s = ("What is the most common letter in this string "); // giving s a string
getMostFreqLetter(s); // caling the function to print out the most freq Letter
return 0;
}
char getMostFreqLetter(string ss) {
int max, index, i = 0;
int array[255] = {0};
char letters[];
// convert all letters to lowercase to make counting letters non case sensative
for (int i = 0; i < ss.length(); i ++){
ss[i] = tolower(ss[i]);
}
//read each letter into
for (int i = 0; i < ss.length(); i ++){
++array[letters[i]];
}
//
max = array[0];
index = 0;
for (int i = 0; i < ss.length(); i ++){
if( array[i] > max)
{
max = array[i];
index = i;
}
}
return 0;
}

If you are not considering white space as letter.
Then more efficient way could have been
vector<int> count(26,0);
for (int i = 0; i < s.length(); i++) {
int range = to_lower(s[i])-'a';
if ( range >= 0 && range < 26)
count[range]++;
}
// Now you can do fix the max while iterating over count;

Use string::c_str().
It converts a string to a character array.

You have a few errors in your code.
Firstly, the array of chars letters is completely unused. You should disregard it and iterate over the string ss instead which is what I think you intended to do.
This would change your second for loop from ++array[letters[i]]; to ++array[ss[i]];.
Secondly, your last for loop is buggy. You are using i as the index to look for the frequency in array whereas you need to use the ascii value of the character (ss[i]) instead. Here is a fixed version with comments:
index = ss[0];
max = array[index];
for (int i = 0; i < ss.length(); i ++){
if(!isspace(ss[i]) && array[ss[i]] > max)
{
max = array[ss[i]]; // you intended to use the ascii values of the characters in s to mark their place in array. In you code, you use i which is the just the index of the character in s as opposed to the ascii value of that character. Hence you need to use array[ss[i]].
index = ss[i];
}
}
return index;
Once you make the above changes you get the following output when run on your string:
Most freq character: t

Related

Reading a Text file and Storing data in 2D Array in C++

Basically, I'm reading a file and trying to store the data in a 2D, for the differentiation between rows and columns I use the logic below:
int rows=0,column=0;
char arr[50][50];
while(my_file.eof()==0){
my_file.get(ch);
if(ch=='\n'){
rows++;
}
arr[rows][column]=ch;
column++;
}
for(int j=0;j<rows;j++){
for(int k=0;k<column;k++){
cout<<arr[j][k];}
}
But the when I run It shows the following output: https://i.stack.imgur.com/XzhST.png
And the text file data is:
I am going to school
hi!
Hello
guide me a bit...
Hmm, a 2D char array can indeed be used to store an number of lines, but you should control that you never try to store more than 50 characters for a single line, and that you never try to ouput more characters for a line than what it initially contained.
Here is a minimal fix of your code:
int rows = 0, column = 0;
char arr[50][50] = { {0 } }; // ensure the array is initialized with '\0' chars
for (;;) {
my_file.get(ch);
if (!my_file) break; // eof shall be tested AFTER a read operation
if (ch == '\n') {
rows++;
if (rows == 50) break; // no more than 50 lines
column = 0; // reset column index for next line
}
else if (column < 50) { // no more than 50 columns
arr[rows][column] = ch;
column++;
}
}
for (int j = 0; j < rows; j++) {
for (int k = 0; k < 50; k++) {
if (arr[j][k] == 0) break; // stop on end of line
std::cout << arr[j][k];
}
std::cout << '\n'; // and display the end of line
}
And as you have been said this is rather C-ish... I assume it is only for learning how 2D arrays can work.
As pointed out in comments, you'd be much better off using a std::vectorstd::string to store the strings.
But, this looks like a homework assignment to read then print each byte separately, so let's have a look... I'll add one of the ways this is usually done at the end of this post.
Your output looks like this:
It looks like you are displaying characters beyond the bondary of the strings, or that your strings are not null terminated... Turns out it's both.
Your code:
int rows = 0, column = 0;
char arr[50][50]; // <-- your array is not initialized, while that is not
// a big issue, filling the array with zeroes is easy:
// char arr[50][50] = {};
while (my_file.eof() == 0) {
my_file.get(ch);
if (ch == '\n') {
rows++; // <-- you pass to the next string, but do not put a
// null character to properly terminate your strings
// while this could have been avoided by initializing
// the array, it's best to do it explicitely.
// replace above line contents by:
arr[row][column] = '\0';
if (++row >= 50) // consider using named constants for the size of your array.
break; // No use keeping on reading strings if there is no
// more room to store them
}
arr[rows][column] = ch; // <-- I suspect a bunch un undefined stuff will
// start happening when column >= 50
column++;
// Try replacing above code with:
if (column < 50) // consider using named constants for the size of your array.
arr[rows][column++] = ch;
}
// make sure the last string is null terminated.
if (row < 50 && column < 50)
arr[row][column] = '\0';
// note that strings that are 50 bytes long are NOT null terminated.
// that's important to keep in mind, and only workss because we'll print
// byte by byte.
// your original print routine prints out all characters in the array, even
// stuff that was not in the original file...
for (int j = 0; j < rows; ++j){
for (int k=0 ; k < column; ++k){ // <-- you need to check for a null
// terminating character here...
// also, column is the length of the last
// string in the array. This is not a very
// useful value for displaying any other
// strings, is it?
// try this:
for (int k = 0; k < 50 && arr[j][k] != '\0'; ++k)
cout << arr[j][k];
}
cout << '\n'; // insert a newline after each string.
}
As you can tell, this is overly complex for doing a very common operation... Here's a more concise way of doing the same thing:
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
int main()
{
std::vector<std::string> arr;
std::ifstream ifs("testfile.txt");
while (ifs && !ifs.eof())
{
std::string str;
std::getline(ifs, str);
arr.push_back(str);
}
for (size_t i = 0; i < arr.size(); ++i)
std::cout << arr[i] << '\n';
return 0;
}
Because you haven't compile the array yet
char arr[50][50];
for (int r = 0; r < 50; r++){
for (int c = 0; c < 50; c++){
arr[r][c] = ' ';}
}

how to split a string to specific length to specific length sub-units and store the value as a vector

Split string using loop to specific length sub-units
string str("0123456789asdf");
for (unsigned i = 0; i < str.length(); i += 4) {
cout << str.substr(i, 4) << endl;
}
so I found this page which is pretty much what I want, but instead of print the values, I need to store them as a vector, this code gives "0123" "4567" "89as" "df", but I need to store them in a vector , also since the last element is "df" I need to attach 2 more "2"s to make it "df22"(i.e. if the desired length is 5 then it should be "01234" "56789" "asdf1" because 5-4=1), is there any way to do that?
Code below:
const unsigned int n = 4;
string str("stackoverflow");
vector<string> strings;
for (unsigned i = 0; i < str.length(); i += n) {
strings.push_back(str.substr(i, n));
}
//difference from subset length and last string length
unsigned post = n - strings.back().size();
for (unsigned i = 0; i < post; ++i){
strings.back().append(to_string(post));
}
string str("0123456789asdff");
vector<string> strings;
int desire_length = 5;
int ss = str.length()/desire_length;
for (unsigned i = 0; i < str.length(); i += desire_length) {
strings.push_back(str.substr(i, desire_length));
}
int c_no = desire_length - strings[ss].length();
if(str.length()%desire_length != 0){
for(int i = 0; i<c_no; i++){
strings[ss] += std::to_string(c_no);
}
}
to_string() function is introduced in C++11.

c++: string.replace inserting too many characters

I'm trying to step through a given string with a for loop, replacing one character per iteration with a character from a vector[char].
Problem is that the replace inserts the entire vector-k instead of the character at place k and I cannot figure out what I've done wrong.
Any and all help is appreciated.
(alphabet is a const string a-z, FirstWord is the given string).
vector<char> VectorAlphabet;
for (int i=0; i<alphabet.length(); ++i)
{
VectorAlphabet.push_back(alphabet.at(i));
}
for (int i = 0; i < FirstWord.length(); ++i )
{
for (int k = 0; k < VectorAlphabet.size(); ++k)
{
string TempWord = FirstWord;
TempWord.replace(i, 1, &VectorAlphabet[k]);
if (CheckForValidWord(TempWord, WordSet))
{
if(CheckForDuplicateChain(TempWord, DuplicateWordSet))
{
DuplicateWordSet.insert(TempWord);
stack<string> TempStack = WordStack;
TempStack.push(TempWord);
WordQueue.push(TempStack);
}
}
}
}
e.g TempWord = tempword, then after TempWord.replace() on the first iteration it is abcde...zempWord. and not aempword. On the second to last iteration of the second for loop it is yzempword.
What have I missed?
Problem solved, thanks to Dieter Lücking.
Looking closer at the string.replace reference, I see that I tried to use a replace which takes strings as the input, and then the vector[char] is interpreted as a c-string, starting from the k-position.
By using the fill-version of replace the vector position is correctly used as a char instead.
New code is:
for (int i = 0; i < FirstWord.length(); ++i )
{
for (int k = 0; k < VectorAlphabet.size(); ++k)
{
string TempWord = WordStack.top();
// Change:
TempWord.replace(i, 1, 1, VectorAlphabet[k]);
if (CheckForValidWord(TempWord, WordSet))
{
if(CheckForDuplicateChain(TempWord, DuplicateWordSet))
{
DuplicateWordSet.insert(TempWord);
stack<string> TempStack = WordStack;
TempStack.push(TempWord);
WordQueue.push(TempStack);
}
}
}
}

Counting words in a c string

I need help completing this function so that it correctly returns the the number of words in the c-string. Maybe my logic is wrong ?
#include <iostream>
#include <string>
#include <cctype>
int countwords(char *, int);
using namespace std;
int main()
{
char a[] = "Four score and seven";
int size = sizeof(a)/sizeof(char);
cout << countwords(a,size);
return 0;
}
int countwords(char* a, int size){
int j = 0;
for(int i = 0; i < size; i++){
if(isspace(i) and isalnum(i - 1) and isalnum(i + 1))
j++;
}
return j;
}
You are passing the value of i to these functions instead of a[i]. That means you're testing if your loop variable is a space (for example), rather than the character at that position in the a array.
Once you have fixed that, understand that you can't blindly reference a[i-1] in that loop (because of the possibility of accessing a[-1]. You will need to update your logic (note also you must use && for logical AND, not and).
I suggest using a flag to indicate whether you are currently "inside" a word. And reset that flag whenever you decide that you are no longer inside a word. eg
int inside = 0;
for (int i = 0; i < size; i++) {
if (alnum(a[i])) {
if (!inside) {
inside = 1;
j++;
}
} else {
inside = 0;
}
}
Also, please use strlen(a) instead of sizeof(a)/sizeof(char). If you continue that practice, you're bound to have an accident one day when you try it on a pointer.
This loop is invalid
for(int i = 0; i < size; i++){
if(isspace(i) and isalnum(i - 1) and isalnum(i + 1))
First of all you does not check characters of the string whether they are spaces or alphanumeric. You check variable i whicj has nothing common with the content of the string. Moreover you have an intention to access memory beyond the array
As you are dealing with a string I would declare the function the following way
size_t countwords( const char *s );
It could be defined as
size_t countwords( const char *s )
{
size_t count = 0;
while ( *s )
{
while ( isspace( *s ) ++s;
if ( *s ) ++count;
wjile ( isalnum( *s ) ++s;
}
return ( count );
}
I do not take into account punctuation symbols. Otherwise you should substitute isspace for !isalnum.
A simpler version would be to repeatedly call strtok() on the string, and each time that an element is returned, you can increment a word count. This would take care of doubled spaces, and so on. You could even split two words with a comma but no space ("this,error") without difficulty.
something along the lines of:
do {
s = strtok(s," ,.;");
if (s) wordcount++;
} while(s);
The only immediate disadvantage is that strtok is destructive, so make a copy before starting.
To count the number of words, you merely need to count the number of times you see a non-whitespace character after a whitespace character. To get things right at the start of the string, assume there is "whitespace" to the left of the string.
int countwords(char* a, int size) {
bool prev_ws = true; // pretend like there's whitespace to the left of a[]
int words = 0;
for (int i = 0; i < size; i++) {
// Is the current character whitespace?
bool curr_ws = isspace( (unsigned char)a[i] );
// If the current character is not whitespace,
// but the previous was, it's the start of a word.
if (prev_ws && !curr_ws)
words++;
// Remember whether the current character was
// whitespace for the next iteration.
prev_ws = curr_ws;
}
return words;
}
You might also notice I included a cast to unsigned char on the call to isspace(). On some platforms, char defaults to signed, but the classifier functions isspace and friends aren't guaranteed to work with negative values. The cast forces all the values to be positive. (More details: http://en.cppreference.com/w/cpp/string/byte/isspace )

Reading from text file into an array

I'm trying to read a textfile that I've edited with Vim into an array.
The textfile is 30*50 and is composed of single digit numbers. I've been going crazy trying to get it to work, but I think I'm having issues due to newline characters. Here's what I've been using:
Map::Map(char* filename)
{
grid[30][50] = (0);
string line;
ifstream m_file(filename);
if (m_file.is_open())
{
while(m_file.good())
{
for (int i = 0; i < 30; i++)
{
getline(m_file,line);
for (int k = 0; k < 50; k++)
{
int tnum = atoi(line.c_str());
grid[i][k] = tnum;
}
}
}
m_file.close();
}
};
grid is defined in the header file as int grid[30][50].
The code I use to print is as follows:
void display_room(int trid[30][50])
{
for (int i = 0; i < 30; i++)
{
for (int k = 0; k < 50; k++)
{
mvprintw(i,k,"%d",trid[i][k]);
};
};
};
after calling Map sMap = Map("testmap");
I'm simply trying to capture the single digit numbers into an array, and reprint that array (using curses). Currently, it reads the testmap file, and prints all zeros, no matter what is in the testmap file.
If I understand Your problem: Your parsing sets the value from the entire line where only a digit should be...
int tnum = atoi(line.c_str());
grid[i][k] = tnum;
Translating the digit (ASCII to an int/byte/... can be done in this way:
grid[i][k] = line[k] - '0';
(Perhaps some casting is needed.)
In the inner loop, you're calling atoi with the full content of the line each time. As the line is 50 character long, atoi cannot convert it to an int (the largest representable value by an int is 2147483647, and your number is probably larger than that). When atoi fails, it return 0.
What you want is convert each character of the line into an int. Something like that:
for (int i = 0; i < 30; i++)
{
getline(m_file,line);
for (int k = 0; k < 50; k++)
{
// The ASCII character of the digits 0 to 9 have
// successives values.
int tnum = line[k] - '0';
grid[i][k] = tnum;
}
}
Look at your code again. Try to see what is actually says instead of what you hope it says
int tnum = atoi(line.c_str());
You clear want that line to read each of the fifty numbers on the line in turn. But it doesn't say that. It tries to turn the whole line into an integer (and tries to do that fifty times).
Since your numbers are single digits, you actually need something much simpler
int tnum = line[k] - '0';
By saying line[k] you will get a different digit each time round the loop (because k increases each time round the loop). The - '0' bit is just a trick to turn a character into an integer. See if you can work out how it works.