2

Can someone help me validate the inputs for the Scanf's i have below. I want the programme to ask for the data to be re-entered if the Scanf's are within an incorrect range or not an interger. I put in a do while loop before with an if statement but when i compiled it the first printf and scanf just looped

#include <stdio.h>
#include <stdlib.h>



int MenuLoop = 0;
int MaxPackets = 4;
int currentPackets= 0; 
int menu;



/*********************************************************
* Node to represent a Cat which includes a link reference*
* a link list of nodes with a pointer to a Cat Struct    *
* would be better but this is for illustartion only!     *
**********************************************************/
struct Packet {
int Source;
int Destination;
int Type;
int Port;
char *Data;
struct Packet *next; // Link to next Cat
};

typedef struct Packet node; // Removes the need to constantly refer to struct


/*********************************************************
* Stubs to fully declared functions below                *
**********************************************************/
void outputPackets(node **head);
void push(node **head, node **aPacket);
node* pop(node **head);
void AddPacket();
void AddPacket();
void SavePacket();
void ShowCurrent();
void ExitProgramme();



main() {

do{

Menu();

} while(menu<4);


}


void AddPacket(){

int option;





/*********************************************************
* pointers for the link list and the temporary P to    *
* insert into the list                                   *
**********************************************************/
node *pPacket, *pHead = NULL;

/*********************************************************
* Create a cat and also check the HEAP had room for it   *
**********************************************************/
pPacket = (node *)malloc(sizeof(node));
if (pPacket == NULL)
{
    printf("Error: Out of Memory\n");
    exit(1);
}

currentPackets++;
printf("Enter Source Number between 1-1024:\n");
scanf("%i", &pPacket->Source);
printf("Enter Destination Number between 1-1024:\n");
scanf("%i", &pPacket->Destination);
printf("Enter Type Number between 0-10:\n");
scanf("%i", &pPacket->Type);
printf("Enter Port Number between 1-1024:\n");
scanf("%i", &pPacket->Port);
printf("Enter Data Numberbetween 1-50:\n");
scanf("%s", &pPacket->Data);
printf("Do you want to Enter another Packet?");
pPacket->next = NULL;

/*********************************************************
* Push the Cat onto the selected Link List, the function *
* is written so the program will support multiple link   *
* list if additional 'pHead' pointers are created.       *
* Who says you cannot herd cats!                         *
**********************************************************
* NOTE: The push parameters are using references to the  *
* pointers to get round the pass by value problem caused *
* by the way C handles parameters that need to be        *
* modified                                               *
**********************************************************/

push(&pHead, &pPacket);

pPacket = (node *)malloc(sizeof(node));
if (pPacket == NULL)
{
    printf("Error: Out of Memory\n");
    exit(1);
}

 outputPackets(&pHead);

/*********************************************************
* Display the Link List 'pHead' is passed as a reference *
**********************************************************/


return 0;


do{
    if(currentPackets == MaxPackets);
{
    printf("Packet limit reached please save\n");

}


}while(currentPackets<MaxPackets);

return 0;
}




void outputPackets(node **head)
{


/*********************************************************
* Copy Node pointer so as not to overwrite the pHead     *
* pointer                                                *
**********************************************************/
node *pos = *head;

/*********************************************************
* Walk the list by following the next pointer            *
**********************************************************/
 while(pos != NULL) {
    printf("Source: %.4i Destination: %.4i Type: %.4i Port: %.4i \n", pos->Source,   pos->Destination, pos->Type, pos->Port);

    pos = pos->next ;
}
printf("End of List\n\n");
}



void push(node **head, node **aPacket)
{
/*********************************************************
* Add the cat to the head of the list (*aCat) allows the *
* dereferencing of the pointer to a pointer              *
**********************************************************/
(*aPacket)->next = *head;
*head = *aPacket;
}

node *pop(node **head)
{
/*********************************************************
* Walk the link list to the last item keeping track of   *
* the previous. when you get to the end move the end     *
* and spit out the last Cat in the list                  *
**********************************************************/
node *curr = *head;
node *pos = NULL;
if (curr == NULL)
{
    return NULL;
} else {
    while (curr->next != NULL)
    {
        pos = curr;
        curr = curr->next;
    }
    if (pos != NULL) // If there are more cats move the reference
    {
        pos->next = NULL;
    } else {         // No Cats left then set the header to NULL (Empty list)
        *head = NULL;
    }
}
 return curr;

}




void SavePacket(){



FILE *inFile ;
char inFileName[10] = { '\0' } ;

printf("Input file name : ") ;
scanf("%s", inFileName) ;

//Open file
inFile = fopen(inFileName, "w+");
if (!inFile)
{
fprintf(stderr, "Unable to open file %s", &inFile);
exit(0);

}

//fprintf(inFile, "Source: %i Destination: %i Type: %i Port: %i \n", pos->Source,     pos->Destination, pos->Type, pos->Port);
fclose(inFile);

}







void ShowCurrent(){



}

void ExitProgramme(){}

void Menu(){


printf("********Welcome****** \n");
printf("Creator Ben Armstrong.\n\n");
printf("*Please Choose an option*\n");
printf("1. Add a new packet\n");
printf("2. Save current packet to file\n");
printf("3. Show current list of packets\n");
printf("4. Exit\n");

scanf("%i", &menu);

    switch(menu)

    {
    case 1:
    AddPacket();
    break;

    case 2:
        SavePacket();
    break;

    case 3 :
        ShowCurrent();
    break;

    case 4 :
    ExitProgramme();
    break;



}


}

This is my full code as u can see im trying to implement a link list which the data has to be validated for

user1949280
  • 75
  • 2
  • 8
  • the same with http://stackoverflow.com/questions/15792984/common-macro-to-read-input-data-and-check-its-validity – MOHAMED May 07 '13 at 15:54
  • Check out [this similar question](http://stackoverflow.com/questions/9462780/in-c-how-can-i-restrict-the-accepted-values-that-this-scanf-will-take). I think you should make a function that takes your int range as args, then performs a readline()/sscanf() loop as indicated in answers from that other post and can manage escape sequences if you want. Also, do you really mean to have "%s" for `&pPacket->Data` when you're asking for a number? – n0741337 May 07 '13 at 16:28
  • could you show us the code using the macro I mentioned in my answer – MOHAMED May 07 '13 at 16:48
  • @n0741337 When i use the method in that similar answer, the code runs without triggering the while loop – user1949280 May 07 '13 at 16:51
  • the Data is defined as `char *` and in your code you say `"Enter Data Numberbetween 1-50:\n"` what do you mean ? – MOHAMED May 07 '13 at 16:53
  • Data need to be entered as a string but is a number between 1-50, this doesnt create a problem within the code.... – user1949280 May 07 '13 at 17:17
  • Where is the memory allocation for the ->Data pointer? Maybe you'd rather have Data defined as char[3] instead of char*? Even though the final representation of Data is a string representation of a number from 1-50, why not accept the value as an integer then convert it to a string? One benefit is that you would only need one function to handle your ranged input data. – n0741337 May 07 '13 at 18:17
  • In my specification im told, Data = char and must be entered as a string containing only numbers :/ – user1949280 May 07 '13 at 18:21
  • You will need to check the return value from each and every `scanf()`; until you do that, your code cannot be reliable. Also see the answers to [What is the reason for error returning a structure in this C program](http://stackoverflow.com/questions/16350807/what-is-the-reason-for-error-while-returning-a-structure-in-this-c-program/16371915#16371915). – Jonathan Leffler May 07 '13 at 18:28
  • When you use scanf(), it's taking an input string and converting it to a different type for you based on the format specifiers. If you absorb Data as a string (%s), you'll have to convert it to an int to test if it's in-range. So why not test if it's in range before storing it as a string in Data? If the specification="homework" I can see why that might be true. And if that's the case, you should limit the max size of your input string with something like "%2s" and make two range helper functions. – n0741337 May 07 '13 at 18:47

2 Answers2

0

Use the following macro

#define SCAN_ONEENTRY_WITHCHECK(FORM,X,COND) \
do {\
    char tmp;\
    while(((scanf(" "FORM"%c",X,&tmp)!=2 || !isspace(tmp)) && !scanf("%*[^\n]"))\
            || !(COND)) {\
        printf("Invalid input, please enter again: ");\
    }\
} while(0)

You find in this topic the macro explaination

Example of using it :

int main()

{

    .......

    printf("Enter Source Number between 1-1024:\n");
    SCAN_ONEENTRY_WITHCHECK("%i", &pPacket->Source, (pPacket->Source>=1 && pPacket->Source<=1024);
    printf("Enter Destination Number between 1-1024:\n");
    SCAN_ONEENTRY_WITHCHECK("%i", &pPacket->Destination, (pPacket->Destination>=1 && pPacket->Destination<=1024);
    printf("Enter Type Number between 0-10:\n");
    SCAN_ONEENTRY_WITHCHECK("%i", &pPacket->Type, (pPacket->Type>=0 && pPacket->Type<=10);
    printf("Enter Port Number between 1-1024:\n");
    SCAN_ONEENTRY_WITHCHECK("%i", &pPacket->Port, (pPacket->Port>=1 && pPacket->Port<=1024);
    printf("Enter Data Numberbetween 1-50:\n");
    SCAN_ONEENTRY_WITHCHECK("%i", &pPacket->Data, (pPacket->Data>=1 && pPacket->Data<=50);

}
Community
  • 1
  • 1
MOHAMED
  • 41,599
  • 58
  • 163
  • 268
  • This returns answers saying #define scan_onentry_withcheck is undeclared within my function and theres an expect ; at the end of input – user1949280 May 07 '13 at 16:16
  • @user1949280 share your code to see your problem. You can shre your whole code in the question – MOHAMED May 07 '13 at 16:20
0

Here is one approach using strtol:

#include <stdlib.h>
#include <stdio.h>

struct Packet {
    int Source;
    int Destination;
    int Type;
    int Port;
    int Data;
};

void func(struct Packet *pPacket) {
    char entry[100];
    int i;
    char *tail;
    do {
        printf("Enter Source Number between 1-1024:\n");
        scanf("%99s", entry);
        i = strtol(entry, &tail, 0);

    } while (*tail || i < 1 || i > 1024);
    pPacket->Source = i;
}

int main(int argc, char* argv[])
{
    struct Packet pPacket;

    func(&pPacket);

    printf("pPacket->Source is now %i.\n", pPacket.Source);

    return 0;
}
A.E. Drew
  • 2,097
  • 1
  • 16
  • 24