2

Hi I'm having a really hard time reading user input in C a specific way...

I want to read a users input, in which case my program will verify the first three characters as characters and the last four digits as digits. And I don't know how to make sure that their input is 7 characters in total (3 chars, 4 ints) ex: ULI0788.

I don't want to use arrays, ex arr[12];

Currently I am at the point where I'm learning memory allocation & pointers, thus I am encouraged to use this rather than arrays if possible

for example

char itemID;
printf("Enter an ID of ITEM. (max 3 characters, 4 digits)");
scanf("%s", itemID);

I've done some googling and tried user suggestions but none do both of what I'm looking for, verifying each character/digit and setting a max of 7 total characters/digits. Or I just don't understand properly how to use the suggestions

googled
googled2
googled3
googled4
googled5
googled6
googled7
googled8
googled9
googled10

16
  • 2
    Not sure what you mean by "not wanting to use arrays". Is this an artificial constraint imposed by your instructor? In the code fragment you posted, it looks like itemID is probably an array Commented Feb 22, 2021 at 12:56
  • 2
    In C, the definition of a string is "a one-dimensional array of characters terminated by a null character '\0'.". Saying you'ld like to use a non-array string is like asking for a glass of water, but make it not wet. Commented Feb 22, 2021 at 13:15
  • 1
    If you're not allowed to use an array, you could use a pointer and call malloc. Not sure whether that would or wouldn't violate the letter or the spirit of your artificial restriction. Commented Feb 22, 2021 at 13:45
  • 1
    @ryyker Saying you'ld like to use a non-array string is like asking for a glass of water, but make it not wet. That's just dehydrated water. Just add water. ;-) Commented Feb 22, 2021 at 14:46
  • 1
    @AndrewHenle - LOL, I was waiting for someone to comment on the, but thought it would be something like, what about ice? Commented Feb 22, 2021 at 14:49

2 Answers 2

5

"I want to read a users input, in which case my program will verify the first three characters as characters and the last four digits as digits. And I don't know how to make sure that their input is 7 characters in total (3 chars, 4 ints)...I don't want to use arrays"

Without the ability to use C strings, the above is constrained to simply inputting a series of characters, then treating and testing them as discrete items:

bool test7char(void)
{
    int Char;

    for(int i=0;i<7;i++)
    {
        Char = getc(stdin);
        if(i<3)
        {
             if(!isalpha(Char)) return false;
        }
        else if(!isdigit(Char)) return false;
    }
    return true;
}

Usage:

int main(void)
{
    printf("Enter an ID of ITEM. (max 3 characters, 4 digits)");
    while(!test7char())
    {
        printf("Mistake - Re-enter an ID of ITEM. (max 3 characters, 4 digits)");
    }
    
    return 0;
}

EDIT - "I am just trying to figure out how to answer my question using memory allocation & maybe pointers"

Using pointer: (In memory, this pointer will point to a series of alphanumeric characters, terminated by \0, i.e. a string.)

#define STR_SIZE 7 + 1
BOOL test7char(const char *str);

int main(void)
{
    char *str = calloc(STR_SIZE, 1);
    if(str)
    {
        printf("Enter an ID of ITEM. (max 3 characters, 4 digits)");
        if(fgets(str, STR_SIZE, stdin))
        {
            while(!test7char(str))
            {
                printf("\nMistake - Re-enter an ID of ITEM. (max 3 characters, 4 digits)");
                if(!fgets(str, STR_SIZE, stdin))
                {
                    //message user of error
                    break;
                }
            }
        }
        free(str);
    }
    
    return 0;
}

bool test7char(const char *str)
{
    if(!str) return false;
    if(strlen(str) != STR_SIZE -1) return false; 

    for(int i=0;i<7;i++)
    {
        if(i<3)
        {
             if(!isalpha(str[i])) return false;
        }
        else if(!isdigit(str[i])) return false;
    }
    return true;
}

    
Sign up to request clarification or add additional context in comments.

Comments

4

I would advise you to use both fgets and sscanf:

  • fgets allows you to read a certain number of characters (which can be read from stdin).
  • sscanf allows you to read formatted input from a string (which you got from fgets).

By combining those, you can read 7 characters from standard input (8 if you add the \0) and then parse those to get the two values you're looking for.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
    // 8 chars long for string and terminating `\0`
    char *ID = calloc(8, 1);
    
    // extra char for same reason as above
    char *IDchar = calloc(4, 1);
    int IDnum, processed;
    
    // get the string and verify it's 7 characters long
    if (fgets(ID, 8, stdin) && strlen(ID) == 7) 
        sscanf(ID, "%3s%4d%n", IDchar, &IDnum, &processed);
    if (processed == 7)
        printf("success");
    else
        printf("failure");
}

The %n will collect the number of characters processed by the sscanf, ensuring you parsed the right number of characters. note that this is a VERY dangerous parameter, and you should always verify your input length before using it.

Edit:

If you do not want to use arrays at all, and only want to verify the input format without storing or reusing it, you can use getc to read the characters one at a time and verify their value:

#include <stdio.h>
#include <ctype.h>
int isEnd(int c)
{
    return c == '\n' || c == EOF;
}
void main()
{
    int tmp;
    int valid = 1;
    //check the first 3 characters
    for(int v = 0; v < 3 && valid; v++)
    {
        // read a char on standard input
        tmp = fgetc(stdin);
        // check if tmp is a letter
        valid = islower(tmp) || isupper(tmp);
    }
    //check the next 4 characters
    for(int v = 0; v < 4 && valid; v++)
    {
        // read a char on standard input
        tmp = fgetc(stdin);
        // check if tmp is a numeral
        valid = isdigit(tmp);
    }
    if (valid)
    {
        printf("format OK\n");
        // Check that the input is finished (only if format is OK)
        tmp = fgetc(stdin);
        if (isEnd(tmp))
            printf("length OK\n");
        else
            printf("length KO: %d\n", tmp);
    }
    else
    {
        printf("format KO\n");
    }
}

As I said before, this will only check the validity of the input, not store it or allow you to reuse it. But it does not use arrays.

Edit 2:

Another thing to watch out for with fgetc or getc is that, though it will manage longer inputs properly, it will get stuck waiting for the chars to be provided if there aren't enough. Thus make sure to exit the moment you read an incorrect character (if it's an end-of-line char, there won't be any more coming)

Edit 3:

Of course I'd forgotten malloc. Edited the first answer.

13 Comments

Have you tried compiling your code? Also, the OP is NOT interested in using arrays.
@QuibbleCoinbiter I have added a potential solution. It has no practical use but it solves your problem
@QuibbleCoinbiter Just check the last edit because the code was not working (swapped first and second inputs for sscanf). Also remember that the first one will not verify whether the first 3 characters are letters or numbers or anything, it will just read them
1. fgetc() returns int, not char. You can not reliably check for EOF if you cram the returned value into a char. 2. isUpperCaseLetter()? What are you recreating standard C functions such as isupper() and isdigit()?
@QuibbleCoinbiter Input validation is really important, so this will be helpful forever. Well, yes and no. There's nothing wrong with Adalcar's answer as an answer to a learning exercise with an artificial constraint. But for real programs, there are much, much better ways of doing input validation than any member of the scanf family. (In particular, in a real program, you would probably want to use a real regular-expression parser, not the limited, pseudo-regular-expression handling of scanf or sscanf.)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.