C++ While loop not working correctly - c++

I am using the following code to break apart a line of text.
A line of text, such as
"adduser john -u 2001 -g 1002 -p john123 -c Project Work"
is passed to the constructor.
I am trying to separate the text by the commands "-u, -g, -p, -c"
"john" will be saved as name,
"2001" will be saved as UID,
"1002" will be saved as GID, etc.
AccountInfo::AccountInfo(char* line){
_line = line;
char bufferLine[256];
unsigned int length1 = 0;
unsigned int tempLength1 = 0;
//find length of line of text
while (_line[length1] != '\0'){
length1++;
}
//separate the text by white space
// start at 8 because adduser is not a command
for (int i = 8; i < length1 + 1; i++){
bufferLine[tempLength1 + 1] = '\0';
printf(bufferLine);
if (_line[i] == ' ')
{
if (bufferLine[0] == '-')
{
//test only u and c commands for now
if (bufferLine[1] == 'u'){
bufferLine[0] = '\0'; //clear contents of array
tempLength1 = 0;
while (!_line[i] == '-'){
bufferLine[tempLength1] = _line[i];
i++;
tempLength1++;
}
bufferLine[tempLength1] = '\0';
printf(bufferLine);
printf("\n This is UID \n");
setUID((unsigned int)bufferLine);
}
else if (bufferLine[1] == 'c'){
bufferLine[0] = '\0';
tempLength1 = 0;
while (!_line[i] == '\0'){
bufferLine[tempLength1] = _line[i];
i++;
tempLength1++;
}
bufferLine[tempLength1] = '\0';
printf(bufferLine);
printf("\n this is gecos \n");
setGecos(bufferLine);
}
}
else{
//is name
bufferLine[tempLength1] = '\0';
setName(bufferLine);
printf("\n I am the user's name\n");
printf(bufferLine);
printf("\n");
}
bufferLine[0] = '\0'; //reset buffer line
tempLength1 = 0; // reset incrementation for buffer line
}
else{
bufferLine[tempLength1] = _line[i];
tempLength1++;
}
}
}
I am working on functionality of the -u command. It reaches the
if (bufferLine[1] == 'u') portion of the code, but always bypasses the while loop following it
while (!_line[i] == '-') I have tried changing the '-' to exit the while loop with ' ' and even any letter 'a' 'g' 'd', however nothing works except '\0'. This is only acceptable for the -c command, as everything after it should be printed.
The -c command works as it should, as does saving the name. However, none of the other commands will work because it does not make it to the loop.
I have been thinking about this problem for a while and I believe it should work, however the code never makes it through the while loop. Is there a problem with the syntax? Or is there something I am missing about nested loops?
Thanks

This expression
while (!_line[i] == '-'){
evaluates as (see operator precedence):
while ((!(_line[i])) == '-') { // because ! has higher precedence than ==
while (false == '-') { // because _line[i] == ' ', !' ' is false
while (false) {
You probably meant
while (_line[i] != '-') {

while (!_line[i] == '-') is essentially while ((!_line[i]) == '-') (note the operators precedence).
What you possibly want is while (! (_line[i] == '-')) { or, simpler, while (_line[i] != '-'){.

!_line[i] == '-'
! has lower precedence than == and is evaluated as
(!_line[i]) == '-'
and this will never be true
http://en.cppreference.com/w/cpp/language/operator_precedence

Related

Leet Code Regular Expression Matching Problem

https://leetcode.com/problems/regular-expression-matching
I was doing this practice problem (cpp) and while faster solutions are in the comments, I would like to understand why my code isn't working. This fails with s = "mississippi" and p = "mis*is*p*.". Tracing through the code, I figured it would correctly remove the first two letters, then when seeing the s* it would go through the s in the string (two of them), then remove the i in both, remove all the s (again 2) then remove all the p's (which is none, because it's compared against the i in the first string, so it should not modify that string). Finally, the '.' would match with the first p and remove both. So the final string should be "pi" and return false when the length is compared to zero.
class Solution {
public:
bool isMatch(string s, string p) {
while (s.length() > 0){
if (p.length() == 0){
return false;
}else if (p.length() == 1){
return p.compare(s) == 0 || p.at(0) == '.';
}else{
if (p.at(1) == '*'){
char c = p.at(0);
p = p.substr(2);
if (c == '.'){
return true;
}
int spot = 0;
while(spot < s.length() && s.at(spot) == c){
spot++;
}
if (spot != 0){
s = s.substr(spot);
}
}else{
if (s.at(0) != p.at(0) && p.at(0) != '.'){
return false;
}
s = s.substr(1);
p = p.substr(1);
}
}
}
return s.length() == 0;
}
};
Your logic is faulty here
return p.compare(s) == 0 || p.at(0) == '.';
That should be
return p.compare(s) == 0 || (s.length() == 1 && p.at(0) == '.');
That took me five minutes to find, two minutes looking at the code without seeing the problem, and then three minutes using a debugger to track down the logic error. You really should learn to use a debugger, much more efficient than asking on SO.
Some tips here.

C++, How to escape special characters from argv without the user manually adding escape characters

I'm writing a program in C++ that can take several input arguments like so:
Edit: based on suggestions from comments
int main(int argc, char **argv) {
constants c;
for (int i=0; i<argc; i++) {
if ( (argv[i])[0] == '-') {
if ((argv[i])[1] == 'h'){
bHelp = true;
//spit out some help text here
}
else if ((argv[i])[1] == 'c' && (argv[i+1]) != nullptr){
c.host = argv[i+1];
}
else if ((argv[i])[1] == 'd' && (argv[i+1]) != nullptr){
c.databasename = argv[i+1];
}
else if ((argv[i])[1] == 'w' && (argv[i+1]) != nullptr){
c.password = argv[i+1];
}
else if ((argv[i])[1] == 'u' && (argv[i+1]) != nullptr){
c.username = argv[i+1];
}
else if ((argv[i])[1] == 'p' && (argv[i+1]) != nullptr){
c.port = argv[i+1];
}
}
}
if (bHelp) {exit(1);}
When run the program seems to work properly, so far so good I thought.
However if any of the input following the flags has special characters for instance a '#' the program segfaults on start.
Whilst you can still make it work by manually escaping such characters on start, with "./app -u testuser -w \#fakepass" for example.
I would rather not bother my end-user with such things and would prefer to solve it in the code.

I/O redirection in C using exe

Here is my code:
#include<stdio.h>
int main()
{
int a = '\0';
while ((a = getchar()) != EOF){
if (a != ' ' || a != '\t' || a != '\n' || a != ';' || a != ',' || a != '.'){
putchar(a);
}
else{
continue;
}
}
system("pause");
return 0;
}
I need to read a poem from an input file, and output the poem with no spaces or punctuation. Must be done using I/O variation. I've searched all over, but I can't seem to find how to do this the way I need. Any help is much appreciated...
Hope this solves your Problem. Use ascii values for character. Also use fgetc/fputc/fscanf/fprintf etc for file i/o related operations. ASCII CHART link here ASCII Chart VALUES.
#include<stdio.h>
int main()
{
FILE *pfile=NULL;
char data[255];
int i=0;
pfile=fopen("poem.txt","r");
while((data[i]=fgetc(pfile)) != EOF)
{
if(data[i]> 32 && data[i] < 123)
{
if(data[i] != 44 && data[i]!= 45 && data[i]!=46 && data[i]!=33)
{
//In the above 'if statement' you can add more characters/special
//characters you wish to exclude/ignore
printf("%c",data[i]);
i++;
}
}
}
return 0;
}

Why isn't the == operator working as expected with char arrays?

For some reason this snippet of code keeps returning 0 even though the token actually equals any specified characters of length 1--either 'M', 'T', 'W', 'R'. Any ideas?
int storeDay(char *token, struct Section s)
{
int length = strlen(token);
cout << "length of token: " << *token << " " << length << endl;
if(length == 2)
{
if(token[0] == 'M' && token[1] == 'W')
{
s.constraints.days[0] = 1;
s.constraints.days[2] = 1;
}
else if(token[0] == 'T' && token[1] == 'R')
{
s.constraints.days[1] = 1;
s.constraints.days[3] = 1;
}
else
return 0;
}
else if(length == 1)
{
if(*token == 'M')
s.constraints.days[0] = 1;
else if(*token == 'T')
s.constraints.days[1] = 1;
else if(*token == 'W')
s.constraints.days[2] = 1;
else if(*token == 'R')
s.constraints.days[3] = 1;
else
return 0;
}
}
The question seems unclear. You are asking why it returns 0 in every case, but you do not have a return statement in every conditional path. It is more important to note whether or not the respective 'constraints' member is being set correctly. Of course, you won't be able to tell that from outside of the function because you're taking the Section object by value. Thereby, s is a copy of whatever you called storeDay with and you don't see the change in the original object.

String Subscript Out Of Range C++: Debug

So I am debugging a runtime error I am getting. "string subscript out of range".
I know where the problem is and what is causing it, yet I am looking for a possible solution that will perform in a similar or identical manner without giving me the error.
Here is the code snippet to where the error occurs. Correct me if I am wrong, the problem is occurring because I am declaring a 0 length string then trying to manipulate an nth element.
std::string VsuShapeLine::GetRunwayNumber()
{
std::string name, nbstr, newnbstr, convnbstr;
int idx,idx2, num, count, pos;
char buf[3];
int idx3=-1;
name = this->GetName();
idx = name.find("ALight");
if (idx == -1)
{
idx = name.find("Lights");
idx3 = name.find_last_of("Lights");
}
idx2 = name.find('_');
idx2 +=3;
nbstr = name.substr(idx2, idx-idx2);
if (idx3 != -1)
idx3++;
else
idx3 = idx+6;
if (name.at(idx3) == 'N')
{
pos = nbstr.length();
if (isalpha(nbstr[idx-1]))
nbstr[pos-1] = _toupper(nbstr[pos-1]);
return (nbstr);
}
else if (name.at(idx3) == 'F')
{
convnbstr = nbstr.substr(0,2);
num = atoi(convnbstr.data());
num +=18;
_itoa(num, buf, 10);
newnbstr = buf;
count = nbstr.size();
if (count > 2)
{
if (nbstr.at(2) == 'l' || nbstr.at(2) == 'L')
newnbstr += 'r';
else if (nbstr.at(2) == 'r'|| nbstr.at(2) == 'R')
newnbstr += 'l';
else if (nbstr.at(2) == 'c' || nbstr.at(2) == 'C')
newnbstr += 'c';
}
pos = newnbstr.length();
if (isalpha(newnbstr[pos-1]))
newnbstr[pos-1] = _toupper(newnbstr[pos-1]);
return (newnbstr);
}
return ("");
}
Btw for whoever is interested the problem was at this line:
if (isalpha(nbstr[idx-1])
At this point nbstr is a string of length 3 and idx' value, the way my program works, is always either 9 or 10.
Also as Retired Ninja mentioned checks should be done after using the string::find function.