C challenge #1
· January 11, 2016
I'm up to Bucky's tutorial #33.
Here's my code, but only part of it works. I get the else statement to print. I can't seem to get the password to work....
printf("Enter your password. The first entry must be an upper case letter. The second must be a special character. The last must be a number.\n");
printf("Thank you. %c%c%c is a valid password.\n",upperletter,specialchar,number);
printf("Your password does not meet the requirements.\n");
Post a Reply
Replies- page 2
|Oldest Newest Rating|
· January 12, 2016
Interesting... Unfortunately it's much harder for me to ask questions that gauge your understanding (and have you respond to them) than it is for you to ask questions about something you don't understand. Would it help if I prompt for questions occasionally? I shouldn't need to, but I'll give it a try. It's probably in your best interest to quote the sections you don't understand when you ask questions about them. I noticed you're pretty good at this.
Another pressing issue is whether an answer to one question tends to raise ten more. If this is the case, you should probably find a new resource to learn from, as there are more questions going unanswered than answered by the guide you're using.
I prefer not to talk about things that are stylistic. If you offend me slightly with your indentation, for example, I probably won't raise it as an issue unless I think it's caused you to perceive functionality incorrectly.
There is nothing special about the variable 'i'; you're right to observe that it's a commonly used identifier for an integer variable. It's mostly a stylistic choice. A questionable one, mind you, as pervasive use of meaningless identifiers can make code difficult to maintain, hence style can affect functionality as I mentioned earlier... Use with care. That's all I have to say on any matters that are mostly stylistic choices.
You can't (and shouldn't) use scanf to read a character into an int. This is a matter of functionality; it's simply not an appropriate type choice. When scanf sees %c, it expects a pointer to character (e.g. char, signed char or unsigned char). You're giving it a pointer to int. That is bad...
As far as scanf is concerned there's a pointer to a single byte, the single byte gets written to but an int occupies more than one byte, and the rest of the bytes don't get assigned a value...
You might notice in six months time your program doesn't function correctly on some platforms, because it uses uninitialised garbage. Hopefully before then you might have noticed compilation warnings hinting to this problem, but unfortunately you probably won't get an error because scanf is a variadic function... Feel free to ask questions about warnings! Try to avoid ignoring them... They're there for a purpose, you know?
Similarly, isupper or isdigit (or any of the other <ctype.h> functions) are only safe to use on unsigned char values and EOF. Again, you won't get a compiler error if you try to use some negative values that aren't EOF, but you might see runtime errors in six months time... Unfortunately it's not yet common for a compiler to perform this kind of analysis and offer warnings, so you probably won't get a warning about this one.
Either change upperletter, specialchar and number to unsigned char or use getchar/fgetc. getchar/fgetc return int, which is common with the types of variables you have defined...
getchar/fgetc return an `unsigned char` value as an int or EOF which is not an unsigned char value... The `<ctype.h>` functions operate on unsigned char value or EOF. Do you see that it's a perfect match? These functions fuse together well, which means you could write something like: int c = tolower(getchar()); and the return value would be converted to uppercase when it's an alphabet character, or left unchanged when it's not... The output for one function is compatible with the input for the other.
This is a great question, and should be given much design thought! I guess it all boils down to:
I mentioned argv, which you might not have seen. That would be most unfortunate, but I'm the one who brought up the question so I'll cover it briefly with an example... Feel free to ask questions.
I think this is what Laura was getting at; you don't need (and shouldn't use) fgets, scanf, getchar or fread for this program.
Of course your program is meant to perform the checking. Note that I've used the term 'string' a number of times, and in fact my code relies upon string processing (hence the '\0' checks). You have a fixed width field that requires the user enter precisely three characters (not including the commas from the format string, which I gather are erroneous). However the exercise speaks about a string. A fixed width field doesn't necessarily contain a string. Do you have any questions?
I also noticed it's quite common for Bucky to post-pone coverage of a topic. I hope he managed to complete the series? If not, that's no big deal, as there are books that have stood the test of time... Any questions about this?
fgets is admittedly much more difficult to abuse. It begs the question, rather than leaving the question unasked. Nonetheless, if you ask the same questions about scanf you'll find it can solve the same problems (and then some).
· January 12, 2016
also, is there something special about "i" in variables? I see it all the time
· January 12, 2016
I appreciate all the help. But since I know practically nothing of C or programming (programming is a lot like my logic class in college, but I wasn't the best at it, so I don't think I'll make programming a career choice), I think I'll need some simpler explanation. Some things on my mind;
1). How do I write my programs so they are based on user input how do I make them interactive? More specifically;
Bucky's tutorials are awesome, but typically he starts out declaring the values of variables outright. for example;
printf("%c is a letter", tuna);
printf("%c is a number", tuna);
He set tuna ='1' in order to demonstrate what the rest of the program does for the sake of the student learning, and I understand this. But, I want to get away from it. I'd like to prompt the user/ make the program interactive. So my question is, how do I leave the variable "open" if you will, so the user can input whatever they choose/ program reads their input/ the program reacts based on that input.
"you do not need to use scanf on your conditions, that doesn't make sense."/ "You are meant to retrieve a string passcode from the user then check all the conditions yourself."
.....it wasn't clear that I was personally to be the one to check the code. I assumed the point of the lesson/challenge was to prompt the user with instructions/ write code to validate they've followed them/ then inform them if they have or haven't followed the directions for a password.
"you do not need all those headers" Yes. However, Bucky did recommend we start getting used to them albeit they may not be necessary yet.
"checking every condition at once isn't such a good idea...." I agree. I did think about this, but I stayed positive and motivated in an attempt to figure out if I could pull it off.
I suppose in that sense scanf is what automatically came to mind. Which leads to my next problem
2). Not quite getting the benefit of fgets over scanf a). in general (aside from what Bucky said about accepting spaces which scanf won't) and b). for this particular exercise.
So again, this is where I'm leaning...
"password must be min of x characters. It must have at least 1 uppercase letter, 1 special character, and 1 number. Enter your password now.
User inputs their password.
program checks it
informs user if they're good to go or not (because of x reason why).
Thanks again for the help. Usually my cries for help in forums are passed over, so it's cool seeing the conversation being generated. Also, I love constructive criticism. It helps me grow and learn. And, I have thick skin, so lay it on (professionally, however). Just be ready for a lot of questions : D because I'm having fun and I want to improve.
Thank you again.
"the only stupid question is one that is never asked/ the worst they can do is say no"
· January 11, 2016
Hi, Laura. I hope you will let me help you find some food for thought today... As you're reading this, try to understand that I wouldn't spend so long writing something up if I didn't think it was for a good reason. I can see potential in you, and I don't mean to seem rude when I say this... Teachers who are unwilling to try new things and to learn new things are not near as useful as those who realise, life is one big lesson and we don't stop learning simply because we've graduated from university or been working for ten years or whatever. I think you're great, but you could be soooo much better!
edit: I'm aware that the formatting is shitpoor. I tried but the editor isn't exactly WYSIWIG if you know what I mean.
The only people you'll find who recommend reading input this way tend to do so either because:
Either way, this is appealing from ignorance. I'd rather not use such a citation, partially because it makes me look ignorant, as though I've just read some advice on a forum and blindly followed it without looking deeper into the issues and forming an educated understanding.
Again, you're not going to find a citation to support that, because it's speculative. By this logic I could say you don't need computers, to support a recommendation that you shouldn't use computers.
Like computers, we don't need many aspects of C; they're purely there for our convenience. It is convenient to be able to convert a sequence of decimal digit characters straight from a stream to an int or what-not, without an intermediate "buffer" (which makes it more optimal, by the way). The "continue;" expression is another example of convenience.
This is really two statements disguised as one. Those statements need to be addressed separately.
According to C11, section 18.104.22.168 paragraph 3...
The emphasis is mine; technically speaking, `fscanf` (and `scanf`, by consequence) gives you an option to provide the size of the array, and then it won't cause an overflow.
I assume you're talking about use of `%s` here, as people who learn about `%[` tend to also learn about maximum field widths along-side. An important point to note is that `%s` serves a subtly different purpose to `fgets`; if you were to use `%511s` to read into an array of 512 char, you would probably find that `fscanf` reads a single whitespace-delimitered token, as opposed to a newline-delimitered token. This forms a unique usecase that `fgets` can't solve on it's own.
If your argument is that people shouldn't use functions without first fully reading and understanding the manual, you're right. C isn't a very beginner-friendly language, unfortunately. Beginners who aren't willing to do a lot of reading should probably stick to a language that doesn't have undefined behaviour, such as Python or Java. Alternatively, reading the manual prior to using a function serves to be colossally useful, even in languages such as Python and Java; by doing so we can:
My response to this may surprise you... It's good that you've correctly understood that `fgets` also doesn't solve this problem fully either; you need to resort to a loop, don't you? No...
Well, surprise surprise, you can solve this problem using `fscanf` (and by consequence `scanf`) alone... Observe:
This also forms a unique usecase for `scanf`. Writing such a `getchar`/`fgetc`-loop is, by contrast, error-proned and tedious. Unfortunately most uses of `getchar`/`fgetc` are as incorrect as most uses of `scanf`/`fscanf`, particularly when used in conjunction with `<ctype.h>` functions (which is rather unfortunate, since `getchar`/`fgetc` are fusional with `<ctype.h>` functions). and the same goes for `fgets`. People tend to think these functions just do whatever is intuitive in their minds, but that which is intuitive is subjective, at least initially.
I hope I've opened your mind, Laura. I spent a long time writing this because I can see that you can be an AWESOME teacher. You just need to keep your mind open, think for yourself and do research to support your beliefs. I know, it can be hard to admit when we're wrong, particularly at first... but it gets easier over time. Trust me, stick in there and step outside of your comfort zone and it'll become second nature to you.
· January 11, 2016
Scanf might be useful for formatted strings, but it is recommended to input all data as strings and convert them yourself.
I try to avoid it whenever I can and now I never really have the need for it. Scanf does not provide a buffer size for input and could cause beginners to buffer overflow. Scanf also does not clean the input stream. There can be cases where fgets also can't clean the stream in cases where the input provided exceeds the size of the buffer, but that is fairly common sense. I have a habit of clearing the input stream myself each time I use it.
· January 11, 2016
Greetings. I don't entirely agree that scanf should be avoided entirely in favour of fgets, as there are operations that scanf can perform that fgets can't. However, I do agree that in this case fgets is the more suitable tool for the job.
Having said that, it's also important to face the issues you're facing when you use scanf. First and fore-most, and this goes for the majority of C-standard functions (e.g. `fopen`, `fgets`, `malloc`), your logic needs to CHECK THE RETURN VALUE... For example:
If you use scanf to read one value, you can expect a successful call to scanf to return 1, so n will be 1 in that case. If you use scanf to read two values, n should be 2, or else you can't rely upon both of the values to be determinate. Thus your logic should probably look something like this:
About the commas in your format string "%c,%c,%c\n", that probably doesn't mean what you think it does. This is telling scanf to expect that the user will enter a comma between the characters, so you'll probably notice scanf returns 1 when you enter input like "abc" instead of "a,b,c".
The \n doesn't mean what you might think it means, either. A single whitespace character of any kind (space, tab, newline, etc) will cause scanf to read and consume as many whitespace characters as possible, so you might notice \n also causes spaces to be discarded.
Secondly, take note of warnings. Your compiler is likely warning you that the type of your scanf arguments are conflicted. On the one hand, when you give `%c` to scanf you tell scanf the argument will be a character pointer. On the other hand, all of your arguments are int pointers. As the C standard says at < http://port70.net/~nsz/c/c11/n1570.html#22.214.171.124p10 >
> ... If this object does not have an appropriate type, or if the result of the conversion cannot be represented in the object, the behavior is undefined.
The appropriate types in this case are char, unsigned char or signed char. Not int.
I'd suggest using `unsigned char`, if you continue to use scanf for this for whatever crazy reason. The reason is that isupper and isdigit are only defined to operate on unsigned char values and the EOF value; any other values will produce undefined behaviour. It's much more compatible with getchar.
It is unfortunate that most people habitually use any and all of these input/output functions incorrectly. Read the manuals and be well informed...
· January 11, 2016
You do not need all those headers.
You do not need to use scanf on your conditions, that doesn't make sense.
You are meant to retrieve a string passcode from the user then check all the conditions yourself.
Also avoid using scanf and use fgets instead.
Checking every condition at once isn't such a good idea, since you could not specifically provide under which condition the passcode failed.
One of the most popular languages of all time.
|Bucky Roberts Administrator|