C++ columns, line up perfectly - c++

So I'm trying to write this code that displays ASCII code in perfect columns, but the columns are perfectly lined up right know. What am I doing wrong?
#include <iostream> // cout
#include <iomanip> // setw
using namespace std;
int main ()
{
int a;
for(a=32;a<=255;++a)
{
cout << a << setw(2) <<static_cast<char>(a)<< setw(20);
}
return 0;
}
This is how I want it to look like,
http://www.asciitable.com/index/extend.gif

This is going to be a bit long, so... working code is at the bottom, everything before it is an explanation.
Columns: A simple approach to having n columns in the same line is to conditionally insert a newline after every n entries. The easiest way to do this is to use modulo arithmetic, treating the first entry as 1 and checking if the remainder when dividing by n is 0.
const int NUMBER_OF_COLUMNS = 5;
// ...
for(a=32;a<=255;++a)
{
cout << /* output... */
<< ((a - 31) % NUMBER_OF_COLUMNS == 0 ? "\n" : "");
}
How this works: We add or subtract from the loop's to treat it as if it started at 1 (in this case, by subtracting 31 because it starts at 32), then use modulo on that value to determine whether it's cleanly divisible by n. If it is, we insert "\n" (newline); if it's not, we insert "" (nothing).
This can also be modified to always output a newline at the end of the loop, without placing cout << endl; or cout << '\n'; outside the loop.
// Change...
<< ((a - 31) % NUMBER_OF_COLUMNS == 0 ? "\n" : "");
// To...
<< ((a - 31) % NUMBER_OF_COLUMNS == 0 || a == 255 ? "\n" : "");
// Inserts "\n" every n columns, OR when a is 255.
Alternatively, you can place the check at the start of the output, and treat the loop's counter as if it started with 0; in this case, we would subtract 32.
const int NUMBER_OF_COLUMNS = 5;
// ...
for(a=32;a<=255;++a)
{
cout << ((a - 32) % NUMBER_OF_COLUMNS == 0 ? "\n" : "")
<< /* output... */;
}
This will place a newline at the very start of the output, although if that isn't desired, it can be avoided by specifically checking that a isn't actually its starting value.
// Change...
((a - 32) % NUMBER_OF_COLUMNS == 0 ? "\n" : "")
// To...
((a - 32) % NUMBER_OF_COLUMNS == 0 && a != 32 ? "\n" : "")
// Inserts "\n" every n columns, unless a is 32.
You can also modify this approach to let the user specify how many columns they want to display, if you so desire.
Spacing: If you pass std::setw() a constant value, it can mess up your formatting in certain places. As it stands, there are two issues with the spacing.
for(a=32;a<=255;++a)
{
cout << a
<< setw(2) // Doesn't take into account the number of digits in a.
<<static_cast<char>(a)
<< setw(20); // Doesn't take into account character 127 not being a graphical
// character.
}
As an alternative, you can output tabs with \t, change which output you apply std::setw() to, or use a little logic to determine what value to pass std::setw().
The first one won't properly line up if the width is a constant. This is because std::setw() affects the next output after it, and casting to char guarantees that this output will always be exactly one character (and therefore, that if you specify width x, it will be padded with x - 1 spaces). There are two ways to solve this: Use std::setw() and std::left before outputting a...
cout << setw(4) << left // Tells cout to make sure a is at least 4 characters,
// padding it at the end if necessary.
// 4 characters are used to account for 3 digits + a space.
<< a
<< /* output... */;
Or apply std::setw() to static_cast<char>(a), as you currently are, but use a little logic to determine the value...
cout << a
<< setw(a < 100 ? 3 : 2) // Set width to 3 if a < 100, or 2 otherwise.
<< static_cast<char>(a)
<< /* output... */;
If we go with the first one, it may be better to move std::left outside the loop, as so:
cout << left;
for(a=32;a<=255;++a)
{
cout << setw(4)
<< /* output.. */;
}
cout << right; // Reset to default.
Since we're not passing std::right or std::internal inside the loop, there's no reason to pass std::left every single time.
On some platforms, character 127 will break the formatting of everything after it, until the end of the line; this is because it isn't actually a graphical character, and thus won't actually be displayed (Unicode has "DEL", and Win32 console fonts have a house, though, so they can display it graphically). The simplest way to work around this is to output one or more tab stops, or \ts, after static_cast<char>(a).
cout << /* output... */
<< static_cast<char>(a)
<< "\t\t"
<< /* output... */;
Wait, what's that ?: thing?: That would be the conditional operator, unofficially known as the "ternary operator". This operator takes 3 operands, and acts like a miniature if ... else statement that can be used as an expression. It is used as:
condition ? true-result : false-result
condition is converted to bool, and can be anything that can evaluate to a boolean value. If true, the operator evaluates to true-result; if false, it evaluates to false-result. This operator looks a bit weird, but is incredibly useful, since it allows conditional logic to be applied in situations where if statements can't be used (such as during variable assignment).
Here, I used it twice:
To conditionally insert a newline into std::cout, after every n columns. Note that it is enclosed in parentheses; this is because it has lower precedence than the << operator. It evaluates to either "\n" or the empty string "", depending on the value of a.
To determine the value to pass std::setw(), if it's applied to static_cast<char>(a) instead of a. It evaluates to 3 if a is less than 100, or 2 otherwise.
So, combining these, we get a final result that looks like this:
#include <iostream> // cout
#include <iomanip> // setw, left, right
using namespace std;
int main ()
{
const int NUMBER_OF_COLUMNS = 8; // Number of columns per line.
cout << left; // Append padding after output.
int a;
for(a=32;a<=255;++a)
{
cout << setw(4) // Pad until 4 characters.
<< a
<< static_cast<char>(a)
<< "\t\t" // Use tabs for spacing.
<< ((a - 31) % NUMBER_OF_COLUMNS == 0 || a == 255 ? "\n" : "");
// Insert newline when specified, and after outputting the last entry.
}
// This isn't necessary since you exit right after, but it's a useful habit to develop
// if you format text for console output frequently.
// Remove if desired.
cout << right; // Reset to default.
return 0;
}
I would also suggest:
1) Moving the using namespace std; inside main() itself, and/or replacing it with:
using std::cout; using std::left; using std::right; using std::setw;
2) Declaring a inside the for loop's condition, as for(int a=32;a<=255;++1).

Try this:
#include <iostream> // cout
#include <iomanip> // setw
using namespace std;
int main()
{
int a;
int count = 0;
for (a = 32; a <= 255; ++a)
{
cout << a << setw(2) << static_cast<char>(a);
if (count != 3)
{
cout << setw(20);
count++;
}
else
{
count = 0;
cout << endl;
}
}
cout << endl;
return 0;
}
PS: if you want to have more columns that are equally long try to change this if (count != 3) and this cout << setw(20); to something like if (count != 6) and cout << setw(9);

I think that you are looking for something like this:
#include <iostream> // cout
#include <iomanip> // setw
using namespace std;
int main ()
{
int a;
for(a=32;a<=255;++a)
{
cout << setw(3) << a << setw(20) <<static_cast<char>(a) << std::endl;
}
return 0;
}
setw(3) comes before the character, and you want 3 instead of 2 as mentioned in the comments.
And you also forgot to print a newline at the end.
To get something that looks like the link, you can do something like this:
#include <iostream> // cout
#include <iomanip> // setw
using namespace std;
int main ()
{
int a;
int nColumns = 14;
for(a=32;a<=255;++a)
{
cout << setw(10) << a << setw(8) <<static_cast<char>(a);
if((a-31)%nColumns == 0)
{
cout<<endl;
}
}
return 0;
}
My online compiler does not show characters from 130 to 255 so a break appears (columns not lining up after 130). If yours can show correctly every character, you should not see any break.
Example

As mentioned before in the comments, you need to ask std::coutfor the correct width before outputting the value, and you need to have a means to output a new line, when you have a certain number of columns. So here is just a small edit to your code (this will have numbers increasing in the row, if you want the values to increase in a column instead of a row, you need to do a bit more math or instead of outputting values directly, have them appended to a string for each line, and then output the values at the end. I'll add the first solution to the end of this answer, since the row-increment answer was already given by someone else :-) ):
#include <iostream>
#include <iomanip>
using namespace std;
int main ()
{
int nocols = 5; // number of columns that you want
for (int a = 32; a < 256; ++a)
{
cout << setw(3) << a << setw(20) << static_cast<char>(a);
if (!((a - 31) % nocols))
cout << endl;
}
return 0;
}
Here is a go at column-increment format:
int nocols = 8; // number of columns that you want
int norows = 1 + (256 - 32 - 1) / nocols; // number of rows
for (int row = 0; row < norows; ++row)
{
for (int col = 0; col < nocols; ++col)
{
int ch = 32 + norows * col + row;
if (ch < 256)
cout << setw(3) << ch << setw(10) << static_cast<char>(ch) << ' ';
}
cout << endl;
}

Related

How to check if a character matches another character in a char array?

I'm currently trying to figure out how I can replace a certain character in a char array using a for loop to check each index position in the array. However, when I assign the correct character to the char variable "letterGuessed" and it is checked it instantly goes to the else statement. This leaves the character as an asterisks. This is the code below:
#include <iostream>
#include <cstring>
void hide_Word(char hide[], int size);
int main()
{
char hiddenWord[] = "Hello";
char displayWord[30] = { 0 };
int length = strlen(hiddenWord);
hide_Word(displayWord, length);
std::cout << hiddenWord << std::endl;
std::cout << displayWord << std::endl;
char letterGuessed;
std::cout << "Enter a character: ";
std::cin >> letterGuessed;
for (int i = 0; i < length; i++)
{
if (displayWord[i] == letterGuessed)
{
letterGuessed == displayWord[i];
}
else
{
std::cout << "*";
}
}
std::cout << std::endl;
std::cout << displayWord << std::endl;
std::cin.get();
return 0;
}
void hide_Word(char hide[], int size)
{
for (int i = 0; i < size; i++)
{
hide[i] = '*';
}
}
When I compile your code I get the warning
main.cpp|27|warning: statement has no effect [-Wunused-value]
for the line
letterGuessed == displayWord[i];
This, for one, means that what you do to make correctly guessed letters visible is achieving nothing. Reading and considering warning messages is really helpful, you know.
I guess that your goal here is to turn the "*", which you filled displayWord with, should be replaced by the correctly guessed character.
That would better be achieved by an assignment using =.
letterGuessed = displayWord[i]; /* still unhelpful */
But that line would still not achieve anything visible.
To change something in the displayWord, it should be what gets the guessed character as a new value, not the other way around.
displayWord[i] = letterGuessed;
This is however still not satisfying, because you don't do this in the right situation.
Let's have a look at the condition which determines when you do it.
if (displayWord[i] == letterGuessed) /* unhelpful */
This will trigger, when the guessed character is an asterisk "*", because displayWord is filled with asterisks early on.
Which means that the condition only triggers if the user guesses an asterisk, which is unlikely. Even if it happens, the result is to overwrite an asterisk with an asterisk.
The condition you need should not check the asterisk-filled displayWord, it should instead check the "Hello"-filled hiddenWord.
if (hiddenWord[i] == letterGuessed)
In total, the code should hence be
for (int i = 0; i < length; i++)
{
if (hiddenWord[i] == letterGuessed)
{
displayWord[i]=letterGuessed;
std::cout << letterGuessed;
}
else
{
std::cout << "*";
}
}
This turns an asterisk in the displayed word into the correctly guessed character at each found position.
Note that I added an output of the guessed letter, to complete the letter-by-letter output. I guess you want to delete that output, or the word-output after the loop, so that the filled in word is only seen once.
Output:
Hello
*****
Enter a character: l
**ll*
**ll*

how to convert an for loop to while loop c++

I'm trying to convert a for loop to while loop in c++ and do some checking for duplicates in a random number generator for generating lotto numbers so far all the stuff i'm trying seems to make the compiler very unhappy and I could really use a few pointers. It's the for loop in the Harray() function that feeds the Balls[] array
that i want to convert to a while loop.
#include<iostream>
#include<cstdlib> // to call rand and srand.
#include<ctime> // to make rand a bit more random with srand(time(0)) as first call.
#include<iomanip> // to manipulate the output with leading 0 where neccesary.
using namespace std;
// Hrand() function create and return a random number.
int Hrand()
{
int num = rand()%45+1; // make and store a random number change 45 for more or less Balls.
return num; // return the random number.
}
// Harray() function create and fill an array with random numbers and some formatting.
void Harray()
{
int Balls[6]; // change the number in Balls[6] and in the for loop for more or less nrs. a row.
for(int x=0; x<=6; x++) //the loop to fill array with random numbers.
{
int a; // made to pass the Balls[x] data into so i can format output.
int m = Hrand(); // calling the Hrand() function and passing it's value in int m.
Balls[x] = m; // throwing it into the array tought i did this because of an error.
a = Balls[x]; // throwing it into int a because of an type error.
cout<<"["<<setfill('0')<<setw(02)<<a<<"]"; //format output with leading 0 if neccesary.
}
cout<<endl; // start new row on new line.
}
// Main function do the thing if compiler swallows the junk.
int main() // start the program.
{
int h; // int to store user cchoice.
srand(time(0)); // make rand more random.
cout<<"How many rows do you want to generate?"<<endl; // ask how many rows?
cin>>h; // store user input.
for(int i=h; h>0; h--) // produce rows from user input choice.
{
Harray(); // calling Harray function into action.
}
return 0; // return zero keep the comipler happy.
}
I would like to always have six diffrent numbers in a row but i don't see how to get there with the for loops i think the while loop is way to go but am open to any suggestion that will work. I'm just starting with c++ i might have overlooked some options.
int x=0;
while(x<6)
{
int a;format output.
int m = Hrand();value in int m.
Balls[x] = m; because of an error.
a = Balls[x];
cout<<"["<<setfill('0')<<setw(02)<<a<<"]";
x++;
}
Here, I also fixed a bug. Since Balls has 6 elements, the last element will be 5. Thus you want x<6 instead of x<=6. That goes for the for loop too.
One drawback of while loops is that you cannot declare local variables with them.
First of all, you should realize that the difference between a for loop and a while loop is mostly syntactic--anything you can do with one, you can also do with the other.
In this case, given what you've stated as your desired output, what you probably really want is something like this:
std::vector<int> numbers;
std::set<int> dupe_tracker;
while (dupe_tracker.size() < 6) {
int i = Hrand();
if (dupe_tracker.insert(i).second)
numbers.push_back(i);
}
The basic idea here is that dupe_tracker keeps a copy of each number you've generated. So, you generate a number, and insert it into the set. That will fail (and return false in retval.second) if the number is already in the set. So, we only add the number to the result vector if it was not already in the set (i.e., if it's unique).
How convert for-loop to while-loop
#include <iostream>
class T545_t
{
// private data attributes
int j;
public:
int exec()
{
// A for-loop has 3 parameters, authors often fill 2 of them with magic
// numbers. (magic numbers are usually discouraged, but are expected
// in for-loops)
// Here, I create names for these 3 for-loop parameters
const int StartNum = 2;
const int EndNum = 7;
const int StrideNum = 2;
std::cout << std::endl << " ";
for (int i = StartNum; i < EndNum; i += StrideNum ) {
std::cout << i << " " << std::flush;
}
std::cout << std::flush;
// A while-loop must use / provide each of these 3 items also, but
// because of the increased code-layout flexibility (compared to
// for-loop), the use of magic numbers should be discouraged.
std::cout << std::endl << " ";
j = StartNum;
do {
if (j >= EndNum) break;
std::cout << j << " " << std::flush;
j += StrideNum;
} while(true);
std::cout << std::flush;
std::cout << std::endl << " ";
j = StartNum;
while(true) {
if (j >= EndNum) break;
std::cout << j << " " << std::flush;
j += StrideNum;
}
std::cout << std::flush;
std::cout << std::endl << " ";
j = StartNum;
while(j < EndNum) {
std::cout << j << " " << std::flush;
j += StrideNum;
}
std::cout << std::endl;
return 0;
}
}; // class T545_t
int main(int , char** )
{
T545_t t545;
return(t545.exec());
}
Ask me where 'j' is declared?
This code is marked as C++, so in this case, I have declared 'j' in the private data attribute 'section' of this class definition. That is where you'd look for it, right?
If your c++ code does not have class, what's the point?

I continually get a "Bus Error" while this is code is being executed?

The purpose of this code is to take a file that has been passed into the program and generate the letter frequency of each letter in the file. In above code, I remove punctuation and convert to lowercase letters.
#include<iostream>
#include<string>
#include<fstream>
using namespace std;
int main()
{
string fileContent = "qr rqh zrxog kdyh eholhyhg lq wkh odvw bhduv ri wkh qlqhwhhqwk fhqwxub wkdw wklv";
int count[26] = { 0 }; // an array the size of the alphabet.
for(int f = 0; f < fileContent.length(); f++) // run til the file end.
{
if(fileContent[f] == 32) // to take care of the spaces.
{
f++; // also tried "continue;" and yeild different and also incorrect results.
}
if(fileContent[f] >= 48 && fileContent[f] <= 57) //take care of numbers.
{
f++; // tried "continue;"
}
count[fileContent[f]]++;
}
for(int p = 0; p < 26; p++)
{
cout << char(p + 97) << ": " << count[p] << endl;
}
return 0;
}
When I run this code I get some accurate frequencies, and some horribly incorrect ones (seems like every other result is wrong, yet after a few letters it trails off into astronomically large numbers). Any way to do this better? what is wrong with this code? As per request I have added some more of the code (including a string with a random 100 in it) as it was apparently not clear enough)
For more context, this program is for a Ceasar shift decoder I'm working on. I am in basic c++ and would greatly appreciate any advise from you more experienced devs. thank you!
In your program, this statement:
count[fileContent[f]]++;
should be:
count[fileContent[f]-97]++; //Assuming that all alphabets are in lowercase
If you do not do -97, it is trying to increase the value at index fileContent[f] of count array, which may be beyond the limit of count array.
Also, make sure to continue in both the if blocks and you don't need to do f++ explicitly in both the if blocks as in the for loop you are already doing f++.
You are doing things the difficult way: using C-style arrays, magic numbers in your code, and risking buffer overflows everywhere.
Compare your code to this:
#include <string>
#include <iostream>
#include <map>
using namespace std;
int main()
{
string fileContent = "qr rqh zrxog kdyh eholhyhg lq wkh odvw bhduv ri wkh qlqhwhhqwk fhqwxub wkdw wklv";
map<char, int> counts;
for (char ch : fileContent)
++counts[ch];
for (char ch = 'a'; ch <= 'z'; ++ch)
cout << ch << ": " << counts[ch] << '\n';
}
Or to print all the map contents (if you do not want to print 0 for letters that did not occur) you can use:
for (auto& item : counts)
cout << item.first << ": " << item.second << '\n';
Exercise for the reader to add in the code to exclude the spaces and numbers. Hint: look up the cctype header.

Coordinate system with an Ordinate and Abscissa

I'm currently having a problem making a code for a Coordinate system.
In the exercise I'm doing, I want to create a coordinate system with an Ordinate/Abscissa and a defined letter (for example dot A)
I must put information for 25 dots and it must control all dots with the same letter. They should be in a circle with a (0;0) coordinate beginning. If the information given about the 25 dots do not meet the set condition the selected dots must have new reentered information to meet the condition without changing the given values of the previous dots(which meet the expectations). It also should have all the information for dots which have 2 positive coordinates
here's the code I made. I'd be really thankful if someone helped me out.
#include <iostream>
#include <cmath>
#include <stdio.h>
using namespace std;
int main(){
int dotX[23];//tri masiva
int dotY[23];
char dotName[23];
for (int i = 0; i<23; i++){// Cikal za vavejdane na masivite
cout << "Abscisa \t" << i + 1 << endl;
cin >> dotX[i];
cout << "Ordinata \t" << i + 1 << endl;
cin >> dotY[i];
cout << "Ime na tochkata" << endl;
cin >> dotName[i];
if (i >= 1){//IF operatora i cikula za obhozhdane na masiva i presmqtane na distanciite
bool flag = true;
while (flag){
double distance = sqrt(pow(dotY[i] - dotY[i - 1], 2) + pow(dotX[i] - dotX[i - 1], 2));//Formula za presmqtane na razstoqniqta
if (distance <= 6) {
char broi;
broi = broi++;
cout << "abscisa \t" << i + 1 << endl;
cin >> dotX[i];
cout << "ordinata \t" << i + 1 << endl;
cin >> dotY[i];
}
else{
flag = false;
}
}
}
}
float i;
for (float i = 0; i > 10, i++;){
float(dotX < 10);
cout << dotName[i] << endl;
}
}
There are a few big problems with your code.
First of all, the syntax for (float i = 0; i > 10, i++;) is completely wrong. It compiles, but that's just a coincidence. The different command in the for loop control structure should be separated by semicolons (;), not commas (,). The correct code would then be for (float i = 0; i > 10; i++). By the way, you made a typo, I think you meant for (float i = 0; i < 10; i++) (otherwise the for loop never runs since i is initialized to 0 and 0 > 10 is false from the beginning).
Second of all, you're initializing the variable i twice: once with float i; and once in the for loop. That shouldn't compile, although with some compilers it does. There are two options on how to do. The first option is to declare the variable outside of the for loop and just assign it without initializing it in the for loop:
float i;
for(i = 0; i < 10; i++){
//some stuff
}
The second option is to simply declare it in the for loop as you did in the first loop:
for(float i = 0; i < 10; i++){
//some stuff
}
Another mistake that you made is to declare i as a float and then try to access dotName[i]. Whatever you put inside the brackets has to be of type int or something similar (unsigned int, long, etc). Putting a float variable inside those brackets won't compile just like that. If you want to index an array with a float, you need to tell the compiler that you want to convert it to an int like this: dotName[(int)i] or dotName[int(i)]. This is called a cast. However, in your case, I would recommend just declaring i as an int.
Also, float(dotX < 10); is completely wrong, I don't really understand what you're trying to do there. I think you meant to do float(dotX[i] < 10);, but that still doesn't make any sense. What you would be doing there would be converting a bool to a float and then doing nothing with the result. That compiles and isn't wrong, but is completely useless. As I said, I don't understand what you want to do there.
Also, broi = broi++; is correct but useless. broi++; is enough. The ++ operator increments broi by one by itself and then returns the result. What the ++ operator does internally is basically this:
int operator++(int &x){
x = x + 1;
return x;
}
So it already increments the variable automatically without you having to do anything. What you did is the same as doing this:
broi = broi + 1;
broi = broi;
Here, the first line represents the ++ operator and the second line represents the = operator. It's clear that the second line is useless, so you can just remove it. In the same way, in your code, you can remove broi =, leaving simply broi++;.
You also did a few things that aren't recommended, but work just fine since the C++ standard supports them.
First of all, using namespace std; is bad practice. It's recommended to omit it and add std:: in front of cin, cout and endl. If you want to know why using namespace std; is bad practice, it's well explained here. However, I must admit that I personally still use using namespace std; since I think it's simpler.
Second of all, the main function is supposed to return 0, so it's recommended to add return 0; at the end of the main function. The return value of the main function tells what made the program close. The value 0 means that the program closed when it was supposed to. Any other values mean that the program crashed. A complete list of what each return value means is available here. Note that C++ supports omitting return 0; and most compilers add it automatically if it is omitted, but it's still recommended to have it. Also, C doesn't support omitting return 0; and in C it will return whatever happens to be in the memory, making it looked like the program crashed when it ended normally.
Also, #include <stdio.h> is C and although it works in C++, it's not recommended. In C++, it's better to use #include <cstdio>. All standard libraries that end with .h in C can be used in C++ by removing .h and adding a c at the beginning. That's also the case with cmath: in C, it would be #include <math.h> and in C++, it's #include <cmath>.
A good version of your code would therefore be:
#include <iostream>
#include <cmath>
#include <cstdio>
int main(){
int dotX[23]; //tri masiva
int dotY[23];
char dotName[23];
for (int i = 0; i < 23; i++){ // Cikal za vavejdane na masivite
std::cout << "Abscisa \t" << i + 1 << std::endl;
std::cin >> dotX[i];
std::cout << "Ordinata \t" << i + 1 << std::endl;
std::cin >> dotY[i];
std::cout << "Ime na tochkata" << std::endl;
std::cin >> dotName[i];
if (i >= 1){ //IF operatora i cikula za obhozhdane na masiva i presmqtane na distanciite
bool flag = true;
while (flag){
double distance = sqrt(pow(dotY[i] - dotY[i - 1], 2) + pow(dotX[i] - dotX[i - 1], 2)); //Formula za presmqtane na razstoqniqta
if (distance <= 6) {
char broi;
broi++;
std::cout << "abscisa \t" << i + 1 << std::endl;
std::cin >> dotX[i];
std::cout << "ordinata \t" << i + 1 << std::endl;
std::cin >> dotY[i];
}
else{
flag = false;
}
}
}
}
for (int i = 0; i < 10; i++){
float(dotX[i] < 10); //Note that I don't understand what you're trying to do here, so I just changed it to something that compiles
std::cout << dotName[i] << std::endl;
}
}

Convert argv[1] into an int and it's digits into an array

I've been trying to create a program in C++ that tries to accomplish this pseudocode:
get argv[1] into int
get int’s digits into array[int length]
for int i = array length; i >= 0;
gen random number into check
if check == array[i]
i
say Number i was check
end if
And I think the part I'm really struggling with is the
get argv[1] into int
get int’s digits into array[int length]
part. In my full code there isn't even an attempt because nothing I've tried works. The error I get the most is that the code compiles, but everytime it tries to cout << "Number 1:" << number I just get Number 1: 0 no matter the actual number I enter. And when 0 == 0 the code doesn't even notice.
My broken propably convention-breaking code follows:
#include <iostream>
#include <string>
int main (int argc, char **argv) {
if (argc == 1 || argc == 3) {
std::cout << "Argument count does not match (one argument expected)\n";
return(-1);
}
std::cout << "Input: " << argv[1] << "\n";
const char* text = argv[1];
int number = atoi(text);
int check = rand() % 10;
std::cout << "Check 1: " << check << "\nNumber 1: " << number << "\n";
if (check == array[i]) {
i++;
std::cout << "Success! Number " << i << " was " << check << ".\n";
}
}
}
TL;DR: My "sort of" number cracker doesn't want to put argv1 into an int with the int's digits being later put into an array.
Feel free to make me feel stupid. Hope the question isn't too specific. I'll expand on details as asked.
EDIT: This is an earlier attempt at conversion:
int array[];
for (int i = strlen(text); i >= 0; i--) {
array[i] = number % 10;
number /= 10;
}
EDIT2: So many responses, no solutions. Thank you for trying to explain this newbie so many things at once. BTW: Git
The earlier attempt is almost good: it's just that you have to actually allocate space for the array, like this:
int array[strlen(text)];
if your compiler supports variable-length arrays as an extension, and
std::vector<int> array;
array.resize(strlen(text));
if you want to stick with standard C++ and follow some good practices.
However, if you want to be tricky, you don't even need to convert the argument to a number:
if (argv[1][i] == check % 10 + '0')
does the trick too. All in all, the complete program would look like this:
#include <iostream>
#include <cstdlib>
int main(int argc, char *argv[])
{
int check = std::rand();
std::cout << check << std::endl;
char *p = argv[1] + strlen(argv[1]);
while (p - argv[1] >= 0) {
if (*--p == '0' + check % 10)
std::cout << "guessed " << p - argv[1] << "th digit" << std::endl;
check /= 10;
}
return 0;
}
Your code is relatively close to being right. You are struggling with the declaration of the array (you must specify the size for it). 32-bit int cannot have more than ten digits, so declaring
int array[10];
should be sufficient.
Before converting the number to an array of digits, check if it is negative, and flip its sign if it is negative:
if (number < 0) {
number = -number;
}
Otherwise, your number%10 trick is not going to work.
When you do the conversion, count how many digits you have. Put the result in actualCount variable: chances are that you are not going to use up all the digits in your array, so
int check = rand() % 10; // 10 is the max, not the actual digit count
should be
int check = rand() % actualCount;
Your argument checking also needs improvement: think what would happen if the user passes five parameters? If you expect exactly one argument, you should write
if (argc != 2) {
std::cout << "Argument count does not match (one argument expected)\n";
return(-1);
}
In order to extract only one digit at a time from a number you have a couple of choices.
For convenience you can use a std::string, inserting the original string (argv[1]) in it, then extracting one char at a time:
#include <string>
...
// put the input in a string
std::string text = argv[1];
for (unsigned i = 0; i < text.size(); i++)
{
// extract only one char, a digit
char ch = text.at(i);
// convert that char in a number
int n = ::atoi(& ch);
// use n
...
}
If you don't want to use std::string, you can always use a c-like array (argv[1] itself):
#include <cstring>
...
for (unsigned i = 0; i < strlen(argv[1]); i++)
{
// extract only one char, a digit
char digit = argv[1][i];
// convert that char in a number
int num = ::atoi(& digit);
// use n
...
}