Newbie needs help

R

Rich Strang

Hi group I am just starting out in C so please go easy on me :)

I have started to write a small command line interpreter, I have got the
program to break down the commands successfully until I introduce a loop
into the main function. Without the loop the program works fine with the
loop the cout doesn't seem to work, I know I am probably being real stupid
but I would really appreciate some help. Please find the code below:

Thanks Guys

Rich

// **** Rich's Command Line Interpreter ****
// Author: Rich Strang
// Date: 08/10/03

#include <stdio.h>
#include <iostream.h>
#include <ctype.h>

//Set Global
const int iDim1Size=10;
const int iDim2Size=80;


//Function Prototypes:
int GetLine(char[]);
int ParseLine(char[], char[][iDim2Size], int);
int PrintTokens(char[][iDim2Size]);

int main(void)
{
char cInput[iDim2Size];
int iInputSize=0;
char cTokens[iDim1Size][iDim2Size];
int iExit=0;

while(iExit==0)
{
// Prints prompt to screen
printf("$ ");

// Retrieve user input
iInputSize = GetLine(cInput);

if(cInput[0] != 'e' && cInput[1] != 'x' && cInput[2] != 'i' && cInput[3]
!= 't' )
{
// Split user input into tokens
ParseLine(cInput, cTokens, iInputSize);

//Print tokens to screen
PrintTokens(cTokens);
}
else
{
iExit=1;
}
}

return 0;
}

//GetLine Function
int GetLine(char cInput[])
{
int iInputSize=0;
char ch;

for( iInputSize = 0; (iInputSize < 80) && ((ch = getchar()) != EOF) && (ch
!= '\n'); iInputSize++ )
{
cInput[iInputSize] = (char)ch;
}
return iInputSize;
}

//ParseLine Function
int ParseLine(char cInput[], char cTokens[][iDim2Size], int iInputSize)
{
int iIndex=0;
int iA1=0;
int iA2=0;

for( iIndex = 0; (iIndex < iInputSize); iIndex++ )
{
if(cInput[iIndex] != ' ' && cInput[iIndex] != '\t')
{
cTokens[iA1][iA2] = cInput[iIndex];
iA2++;
}
else
{
iA1++;
iA2=0;
}
}
return 0;
}

//Print Tokens Function
int PrintTokens(char cTokens[][iDim2Size])
{
int iIndex1=0;
int iIndex2=0;

for( iIndex1 = 0; (iIndex1 < iDim1Size); iIndex1++ )
{
for( iIndex2 = 0; (iIndex2 < iDim2Size); iIndex2++ )
{
if ( isalpha(cTokens[iIndex1][iIndex2]) ||
isdigit(cTokens[iIndex1][iIndex2]))
{
cout << cTokens[iIndex1][iIndex2];
}
}
cout << "\n";
}

return 0;
}
 
J

John Carson

Rich Strang said:
Hi group I am just starting out in C so please go easy on me :)

I have started to write a small command line interpreter, I have got
the program to break down the commands successfully until I introduce
a loop into the main function. Without the loop the program works
fine with the loop the cout doesn't seem to work, I know I am
probably being real stupid but I would really appreciate some help.
Please find the code below:

Thanks Guys

Rich

This is all being done in a rather C style without making full use of the
C++ library, e.g., you can use cin.getline rather than your GetLine. But the
problem with your loop has to do with the use of && when it should be ||.
if(cInput[0] != 'e' && cInput[1] != 'x' && cInput[2] != 'i' &&
cInput[3] != 't' )

This condition evaluates to true only if the first letter is not e AND the
second letter is not x AND the third letter is not i AND the fourth letter
is not t. This means, for example, that if the first word is

This

then the condition evaluates to false since cInput[2] != 'i' is false. You
want the condition to evaluate to true provided the first four letters do
not spell "exit", which will be true if ANY of the letters is wrong. Thus
your condition should be:

if(cInput[0] != 'e' || cInput[1] != 'x' || cInput[2] != 'i' || cInput[3] !=
't' )
 
J

Jon Bell

[...] Without the loop the program works fine with the
loop the cout doesn't seem to work, [snip]
if(cInput[0] != 'e' && cInput[1] != 'x' && cInput[2] != 'i' && cInput[3]
!= 't' )

Here's your problem. You want to exit the loop when the user types
"exit", right? That means you want to exit when

cInput[0] == 'e' && cInput[1] == 'x' && cInput[2] == 'i' &&
cInput[3] == 't'

Your loop design means that you actually need the *opposite* of this
condition, which is *not* what you wrote above, but rather

cInput[0] != 'e' || cInput[1] != 'x' || cInput[2] != 'i' ||
cInput[3] != 't'

Think about it a bit, and if you don't "get" it, look up DeMorgan's Rule
in a logic primer or a Google search.

Now, here's a piece of general advice. You must be using an old C++
textbook (pre-1998 or thereabouts), because standard header files don't
have .h in them, and the standard came into existence around 1998.
Post-1998 standard C++ has stuff in it that greatly simplifies what you're
trying to do. Parsing text character by character just to split up
whitespace-separated tokens is *sooo* 1990s. ;-)

Here's my stab at what I think you're trying to accomplish, in more or
less 21st-century C++ style:

#include <iostream>
#include <cctype>
#include <vector>
#include <string>
#include <sstream>

using namespace std;

// no need for your GetLine function, standard C++ has one already
void ParseLine (const string& cInput, vector<string>& cTokens);
void PrintTokens (const vector<string>& cTokens);

int main ()
{
// strings are like arrays of char on steroids
string cInput;
// vectors are like arrays on steroids
vector<string> cTokens;
int iExit = 0;
while (iExit == 0)
{
cout << "$ ";
getline (cin, cInput); // cInput automatically expands as needed
// to accommodate the input
ParseLine (cInput, cTokens);
if (cTokens[0] == "exit") // can compare strings w/o any fuss
{
iExit = 1;
}
else
{
PrintTokens (cTokens);
}
}
return 0;
}

void ParseLine (const string& cInput, vector<string>& cTokens)
{
cTokens.resize(0); // empty out the vector from the previous line
istringstream linestream (cInput);
string token;
// read from an istringstream just like you read from cin;
// this reads whitespace-separated tokens until it hits the
// end of the stream
while (linestream >> token)
{
cTokens.push_back(token); // cTokens automatically expands
// as needed
}
}

void PrintTokens (const vector<string>& cTokens)
{
// note vectors and strings can tell you how big they are, so you
// don't have to keep track of it yourself
for (int iIndex1 = 0; iIndex1 < cTokens.size(); iIndex1++)
{
for (int iIndex2 = 0; iIndex2 < cTokens[iIndex1].length();
iIndex2++)
{
// isalnum means "isalpha || isdigit"
if (isalnum (cTokens[iIndex1][iIndex2]))
{
cout << cTokens[iIndex1][iIndex2];
}
}
cout << '\n';
}
}

Personally, I'd write a separate function to strip the non-alphanumeric
stuff out of a token:

string StripNonAlnum (const string& token)
{
string newToken;
for (int k = 0; k < token.size(); ++k)
{
if (isalnum(token[k]))
{
newToken += token[k];
}
}
return newToken;
}

void PrintTokens (const vector<string>& cTokens)
{
for (int iIndex1 = 0; iIndex1 < cTokens.size(); iIndex1++)
{
cout << StripNonAlnum (cTokens[iIndex1]) << '\n';
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,102
Messages
2,570,645
Members
47,247
Latest member
GabrieleL2

Latest Threads

Top