The primary purpose of this program is to practice catching if the user enters data that does not correspond to expected input. Note if the user enters their name as "123", this is valid as it can be used as an identity, however if users enter only spaces (i.e. " ") or just a newline char then their input will be rejected. Also note preceding and trailing spaces are OK as long as there is some form of symbol present in the entire name.
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#define BUFFSIZE 10
/*Checks to see if name contains actual characters and not just whitespace*/
bool isThereChars(const char * name)
{
bool charCheck = false;
for (size_t index = 0; index < BUFFSIZE; ++index) {
if (name[index] != ' ' && name[index] != '0円')
charCheck = true;
}
return charCheck;
}
void retreiveName(char* name)
{
for (;;) {
if (fgets(name, BUFFSIZE, stdin) != NULL) {
name[strcspn(name, "\n")] = '0円';
if (name[0] == '0円' || isThereChars(name) == false) {
printf("Invalid name entered please try again...\n");
}
else
return;
}
else
printf("Memory could not be allocated please try again...\n");
}
}
int main(void)
{
char name[BUFFSIZE];
printf("Enter Name: ");
retreiveName(name);
printf("Your name is: %s\n", name);
printf("Press enter to continue...\n");
getchar();
return 0;
}
1 Answer 1
Nitpick
void retreiveName(char* name)
This should be
void retrieveName(char* name)
Bugs
if (name[index] != ' ' && name[index] != '0円')
What happens if I enter tabs or unprintable characters? This code would pass a string of all tabs. Is an all numbers string valid?
if (isalpha(name[index]))
Now we check to see if there is a letter rather than excluding only two bad values.
The <ctype.h>
header has this and other functions that you can use. E.g.
if (isprint(name[index]) && !isspace(name[index]))
This might be what you want if you have a really liberal definition of name
.
What happens if you call retrieveName
twice with the same character array? In particular, let's give it an input of "Christopher".
#define BUFFSIZE 10
Christopher has eleven letters, so it overwhelms the buffer size. That's OK the first time, but the second call would get the remainder of the first call, not a new name. So the second time you'd be processing the string "r0円ristophe"
. That includes a letter, so it will return true. Not great, since we wanted a new name.
Now let's change that a bit. Instead of Christopher, enter " Chris ". Again, that's eleven characters. It overwhelms the buffer. The second call results in the string " 0円Chris "
. Now, you
for (size_t index = 0; index < BUFFSIZE; ++index) {
When index
is 2, it finds a C, which is neither a space nor a null. So the function returns true on a string that everything else will interpret as " "
. Oops!
And note that this could also happen with two calls that don't overwhelm the buffer. E.g. the strings "Chris" and " " will call it with " 0円ris0円0円0円0円"
the second time, assuming the character array was zero-initialized.
Consider instead
for (size_t index = 0; index < BUFFSIZE && name[index] != '0円'; ++index) {
Then the loop will stop at the end of the buffer or the end of the string, whichever comes first.
What about other lengths?
bool isThereChars(const char * name)
This only works with one size of buffer. It would make more sense to allow arbitrary length buffers.
bool hasLetter(const char * name, int bufferLength)
This allows the caller to specify a buffer length.
I also like the name hasLetter
better than isThereChars
. Your mileage may vary. Another option is hasAlpha
, to match isalpha
.
No need for a flag variable
bool charCheck = false; for (size_t index = 0; index < BUFFSIZE; ++index) { if (name[index] != ' ' && name[index] != '0円') charCheck = true; } return charCheck;
I'd like this better as something like
for (size_t index = 0; index < BUFFSIZE && name[index] != '0円'; ++index) {
if (isalpha(name[index])) {
return true;
}
}
return false;
This also has the side effect of returning as soon as you find an alphabetic character rather than processing all the other characters even though they won't change the answer.
-
\$\begingroup\$ Thank you for taking the time ans going through and catching those errors, and also explaining what happens with examples! Big help because now i see whats going on! \$\endgroup\$chris360– chris3602016年09月08日 17:52:57 +00:00Commented Sep 8, 2016 at 17:52
-
\$\begingroup\$ I am trying to rerun the code using the isalpha function like you showed and Microsoft Visual Studio is aborting the program with a debug assertion error, any idea as to why this is happening? I've looked around for a good hour and tested several times and am still unsure as to why its throwing the assertion error. Thanks! \$\endgroup\$chris360– chris3602016年09月08日 18:58:30 +00:00Commented Sep 8, 2016 at 18:58
-
\$\begingroup\$ Note I found out what causes this error! passing a variable x, to any ctype function must be an unsigned char or the MACRO value of the EOF. Therefore changing my char array to that of type unsigned mad the program execute without errors! \$\endgroup\$chris360– chris3602016年09月08日 19:30:17 +00:00Commented Sep 8, 2016 at 19:30