• Hey, guest user. Hope you're enjoying NeoGAF! Have you considered registering for an account? Come join us and add your take to the daily discourse.

C programming: Could use a little help...

Status
Not open for further replies.

Vieo

Member
I've been writing a roman numeral converter off and on for several months. I just decided today to fool around with it some more. The program works as long as the user enters the roman numeral correctly, so I'm working on a function thats supposed to handle errors when the user enters bad data. Anyway, I'm having trouble with the OR-operator ( || )

here's a segment..


void errorp(char a[])
{
int count=0;

while(a[count] != '\0'){

if(a[count] != 'I' || 'V' || 'X' || 'L' || 'C' || 'M' || 'D'){
printf("Waffles!\n");
}
count++;
}
}



See, the idea is that when you enter something that's not part of a roman numeral, you'll get the "Waffles!" message. But when I type in a valid roman numeral, I still get the waffles message. Is that not correct usage of the || operator?

When I type in something like X for example, I expect it to go... "OK, the first spot in this array isn't equal to char I, V, L, C, M, D, however, it is equal to char X, so I won't print the waffles message." but it doesn't do that. =P
 

darscot

Member
void errorp(char a[])
{
int count=0;

while(a[count] != '\0')
{
char test = a[count];
if(test != 'I' && test != 'V' && test != 'X' && test != 'L' && test != 'C' && test != 'M' && test != 'D')
{
printf("Waffles!\n");
}
count++;
}
}

Not sure were my tabs went? I didnt run it but I think that will do it.
 

SteveMeister

Hang out with Steve.
|| needs to be separated by expressions that evaluate to true or false.

If you want to chain a bunch of conditions like that, you have to repeat the a[count] !='s each time. And in your case, you want &&'s anyway, because you don't want the value to be ANY of the ones you list.

There are more clever ways to do it, but you probably want this instead:

Code:
 if ( ( a[count] != 'I' ) && ( a[count] != 'V' ) && ( a[count] != 'X' ) && ( a[count] != 'L' ) && ( a[count] != 'C' ) && ( a[count] != 'M' ) && ( a[count] != 'D' ) )
{
  printf("Waffles!\n");
}
 

Makura

Member
And by old school, you mean...

I guess what I'm asking is - if I learn C, would that knowledge be useless if I moved on to working in C++?
 

SteveMeister

Hang out with Steve.
The code above would be identical in C++.

Basically, C++ adds the concepts of object-oriented programming to C. Syntactically the languages are very much the same.

But if you want to be a programmer, you really need to learn object-oriented programming, and that pretty much means C++ and/or Java.
 

Nerevar

they call me "Man Gravy".
Makura said:
I guess what I'm asking is - if I learn C, would that knowledge be useless if I moved on to working in C++?


The real question is, why would you want to learn C and not learn C++?
 
Here is a more compact solution:

Code:
if( !( a[count] == 'I' || 'V' || 'X' || 'L' || 'C' || 'M' || 'D' ) )
{
   printf( "Waffles!\n" );
}
The expression ( a[count] == 'I' || 'V' || 'X' || 'L' || 'C' || 'M' || 'D' ) will be evaluated as either true or false. We can reverse it using the ! operator.

For example, if a[count] is a Roman numeral:
( a[count] == 'I' || 'V' || 'X' || 'L' || 'C' || 'M' || 'D' ) = true
!( true ) = false
Therefore, because the evaluation of the if statement is false, nothing will be printed. Make sense?
 

SteveMeister

Hang out with Steve.
You call that compact? Here's how I would have done it:

Code:
if ( !strchr( "IVXLCMD", a[count] ) )
    printf( "Waffles!\n" );

So HAH! ;)
 

RiZ III

Member
You can't learn C++ without learning C. Im not saying you have to learn C first, its just that C++ is an extension of C. Besides, its not like C is dead, C is still used today.
 

maharg

idspispopd
RiZ III said:
You can't learn C++ without learning C. Im not saying you have to learn C first, its just that C++ is an extension of C. Besides, its not like C is dead, C is still used today.

This is a misleading statement. C++ is far far more than an 'extension' of C. It is a superset, (and even that is not so true since 1999 as it was before) but to say it is an extension implies that the correct and normal way of doing something in C will be the same as in C++, just that C++ allows you to do seperate things.

The notion that C++ is simply an extension of C contributes to more bad C++ code than any other factor I can think of. You CAN learn them in entirely different ways, and I would easily argue that it is highly important to do so.

BugCatcher said:
Here is a more compact solution:

Code:
if( !( a[count] == 'I' || 'V' || 'X' || 'L' || 'C' || 'M' || 'D' ) )
{
   printf( "Waffles!\n" );
}
The expression ( a[count] == 'I' || 'V' || 'X' || 'L' || 'C' || 'M' || 'D' ) will be evaluated as either true or false. We can reverse it using the ! operator.

For example, if a[count] is a Roman numeral:
( a[count] == 'I' || 'V' || 'X' || 'L' || 'C' || 'M' || 'D' ) = true
!( true ) = false
Therefore, because the evaluation of the if statement is false, nothing will be printed. Make sense?

I hope you aren't actually suggesting this is correct code. In fact, the statement you claim will be evaluated as either true or false will always evaluate to true. This is the logic process you're talking about here:
r1 = (a[count] == 'I') (can be true or false, depending on the value of a[count])
r2 = r1 || 'V' (will always be true because 'V' is non-zero, thus evaluates to true. false || true == true, true || true == true)
r3 = r2 || 'X' (and so on, always true).
 
I hope you aren't actually suggesting this is correct code. In fact, the statement you claim will be evaluated as either true or false will always evaluate to true. This is the logic process you're talking about here:
r1 = (a[count] == 'I') (can be true or false, depending on the value of a[count])
r2 = r1 || 'V' (will always be true because 'V' is non-zero, thus evaluates to true. false || true == true, true || true == true)
r3 = r2 || 'X' (and so on, always true).
Oh whoops, you got me. This is the logic I intended:

Code:
if( !( a[count] == 'I' || a[count] == 'V' || a[count] == 'X' || a[count] == 'L' || 
a[count] == 'C' || a[count] == 'M' || a[count] == 'D' ) )
I believe that is correct. Compare this to the other example:
Code:
if ( ( a[count] != 'I' ) && ( a[count] != 'V' ) && ( a[count] != 'X' ) && ( a[count] != 'L' ) && 
( a[count] != 'C' ) && ( a[count] != 'M' ) && ( a[count] != 'D' ) )
Do you understand what I am trying to do? I just wanted to show is that (!a && !b) = !(a || b), but I wasn't paying attention when I copy/pasted Vieo's code. I guess I should have written it myself :) Thanks for catching my mistake.
 

Lathentar

Looking for Pants
This is C++ style, but...

Code:
std::string s = "IVXLCMD";
if(s.find(a[count]) == std::string::npos)
   std::cout << "ROFL my Waffles!" << std::endl;

Or for more fun

Code:
#include <algorithm>
#include <string>

bool roman(char elem)
{
    std::string s = "IVXLCMD";
    return s.find(elem) != std::string::npos;
}

int errorp(string a)
{
   return std::count_if(a.begin(), a.end(), roman);
}

That should work.
 

maharg

idspispopd
Code:
#include <algorithm>
#include <string>

struct roman 
{
  bool operator()(char elem)
  {
    std::string s = "IVXLCMD";
    return s.find(elem) != std::string::npos;
  }
};

int errorp(string a)
{
   return std::count(a.begin(), a.end(), roman());
}

But really, getting out of the obscure (but powerful) algorithm usage, better use of the standard library would be
Code:
#include <string>

int errorp(const std::string &a)
{
  return a.find_first_not_of("IVXLCMD");
}

:)
 

Chrono

Banned
heh, I just finished my intro java course and got a C+. I should've got a B+ though. There was a question where the prof. wanted to repeat the process 3 times.. So I did a loop where you enter n and it repeats n times. You can do it for 3 or 30 times if you want but nooooo... YOU MUST FOLLOW TEH PROF. ALGHEROTH3M AND REPEAT SAME LINES 3 TIM3S!!

Bastard.

I also purposely missed 3 projects just to read other intro java books. I panicked at the beginning of the course and though programming was a sign of the apocalypse and didn't want to take on those RIDICOUSLY EASY projects until reading other material on java and familiarizing myself.


Oh and one question on the final was almost exactly like Vieo's program!

We had to count all a to z (lower and upper cases) and numbers 0 to 9 in a string... Of course the test was on freaking' paper and not a pc so I could not test it. After I went home I wrote it again and it only counted the letters. :(

Come to think of it I think I could've used the PCs in lab. The lab question was stapled to the test and not given after you finish the lecture test like the previous midterms... so maybe I could've tested it? *sobs*
 

Lathentar

Looking for Pants
Maharg, is there any real benefit to using a function object there? And we both messed up. You have to use count_if not count.

Oh and Chrono, if you purposefully missed 3 easy java projects just to read more, you deserve the C+.
 

Chrono

Banned
Lathentar said:
Oh and Chrono, if you purposefully missed 3 easy java projects just to read more, you deserve the C+.


I guess you're right. :eek:

Though I didn't mess them "just to read more." I just gave them one look and though I'd never know how to solve them.. Anyway, I should've taken everything step by step and not worry. What's worse is that those projects are worth as much points as the latest ones that deal with classes and objects. Also, I need only 1 point to get a B. >__<
 

maharg

idspispopd
Essentially, there is a performance benefit. Using the type to define the action allows inlining of the code involved while a function pointer arguably requires an indirection on ever loop iteration.

There are other benefits for more advanced code. The ability to hold data across calls to the object while still being reentrant is an obvious one. And if you do it really properly (derive from std::unary_function or std::binary_function or provide a similar/identical interface) you can more easily deduce the return type or argument types and have your code optimize based on those. You can also overload multiple call signatures and have it work without extra effort at the call site, wheras with a function pointer you need to use a cast to disambiguate.

In the end, even though simple uses don't gain a lot, consistancy is a good thing, so I tend to err on the side of functor-objects when it's going to be used algorithmically.
 

NotMSRP

Member
A good modern programmer knows at least these: Java, C++, C, and Assembly. You may primarily use Java and C++ on the job, but knowing the other two helps you have a deeper understanding of computer concepts.
 

Swordian

Member
Chrono, I haven't done much programming for a while now, but at the risk of sounding stupid my guess would be you need '0' and '9'.
 
This thread is becoming really informative! I hadn't heard of function objects before, so I read up on them and learned something new :)

maharg, is there any benefit to making roman a struct and not a class? Just curious; you know this stuff better than me.

Also, there's something I've been wondering for a long time, but nobody I've asked has the answer. What is wrong with switch/case? I don't use it in my code, but I've heard plenty of programmers who are smarter than me talk about it with disgust. I never found out the reason, but I avoid it nonetheless.
 

Chrono

Banned
Swordian said:
Chrono, I haven't done much programming for a while now, but at the risk of sounding stupid my guess would be you need '0' and '9'.

I feel so stupid. 0 and 9 are used as numbers not characters-- yeah I should've had them in single quotes. I just tried it and now it works... *cries*

Thanks. :p
 

maharg

idspispopd
Struct's default access specification is public, class' is private. In fact, this is the only 'real' difference between a struct and a class in C++ (contrary to somewhat popular belief). As such, the tendency is to use struct when a class has no private interface to make the code arguably more readable.

Some people feel that switch is too low level and allows for risky code. Especially because of the ability to drop through another case statement. Personally, I have no problem with them, but in modern code they aren't always much of an option since they only work on integral types.
 

Lathentar

Looking for Pants
BugCatcher said:
Also, there's something I've been wondering for a long time, but nobody I've asked has the answer. What is wrong with switch/case? I don't use it in my code, but I've heard plenty of programmers who are smarter than me talk about it with disgust. I never found out the reason, but I avoid it nonetheless.

Switch should only be used when you know the contents of the switch statement aren't going to change. For example, if you define a switch over directions you can be fairly confident you aren't going to be adding another direction.

In all other cases, you want to take advantage of object-oriented programming and use polymorphism.
 

fart

Savant
i'm surprised no one else is shocked to learn that he's been working on this for several months.

i'm a pioneer.
 
Status
Not open for further replies.
Top Bottom