Jacob Greene
Jacob Greene

Reputation: 1

scanf picking up characters after whitespace C

I am writing a program that takes a line of user input and stores the data in a struct that is then used in a linked list. The data is entered in the following format: command_name full_name address account_balance

command_name calls the function;

full_name is a single char array with a dash instead of a space.

address is a single char array with street,city,state,zip all separated by a comma

account_balance is a double.

I have a function to replace the '-' and ',' chars with spaces so they contain whitespace.

The issue I am having is that when I read the address the state is read as the state and zip stuck together. The zip is read fine and all other input is read fine. Just the state. It is slowly driving me into madness so I have decided to ask for help. I've attached the code of the insert and print methods below along with a sample printout of a struct.

Input: insert rick137 schwifty-ln,mango,nc,28105 2500

Sample output:

rick137
schwifty ln
mango, nc28105 28105
  2500.00

Desired output:

rick137
schwifty ln
mango, nc 28105
  2500.00

Below is my code:

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

#define NAME_LEN 40
#define ADDRESS_LEN 98
#define MENU_LEN 11

  typedef struct customer {
        char full_name[NAME_LEN+1];
        char address[ADDRESS_LEN+1];
        char street[55];
        char city[32];
        char state[2];
        char zip[5];
        double account_balance;
        struct customer *next;
    }customer;

    customer *database = NULL;

 int strcasecmp(const char *s1, const char *s2);

 void rem_dash(char * str);

 void rem_dash(char *str){
     int i=0;
     while(str[i]!='\0')
     {
           if(str[i]=='-')
           {
               str[i]=' ';
           }  
           i++; 
     }
 } 

 void rem_comma(char *str);
 void rem_comma(char *str){
     int i=0;
     while(str[i]!='\0')
     {
          if(str[i]==',')
          {
              str[i]=' ';
          }  
          i++; 
     }
 }

 void split_add(char *address, char *street, char *city, char *state, char *zip);

 void split_add(char *address, char *street, char *city, char *state, char *zip){

    rem_comma(address);

    printf("%s\n", address);

    sscanf(address, "%s %s %s %s", street, city, state, zip);

    rem_dash(street);
    rem_dash(city);
    rem_dash(state);
    rem_dash(zip);

 }


    void insert_customer(void);

    void insert_customer(void){

        customer *current, *prev, *new_customer;

        new_customer =  malloc(sizeof(struct customer));
        current=NULL;
        prev=NULL;

        if(new_customer==NULL){
            printf("Database full, cannot add more customers.\n");
            return;
        }

        scanf("%40s %98s %lf", new_customer->full_name, new_customer->address, &new_customer->account_balance);

        rem_dash(new_customer->full_name);


        printf("%s\n", new_customer->full_name);

        split_add(new_customer->address,  new_customer->street,  new_customer->city,  new_customer->state,  new_customer->zip);

        //printf("%s\n%s, %s %s\n", new_customer->street, new_customer->city, new_customer->state, new_customer->zip);


       current=database;
       prev=NULL;

       for (;current != NULL;prev = current, current = current->next){

         if (current != NULL && strcmp(new_customer->full_name, current->full_name)==0) {
            printf("DUPLICATE RECORD\n");
            free(new_customer);
            return;
            }
        }

       current=database;
       prev=NULL;

       while(current != NULL && strcmp(current->full_name, new_customer->full_name)<0){
          prev=current;
          current=current->next;
       }

       new_customer->next=current;

       if(prev==NULL){
           database=new_customer;
       }
       else{
           prev->next=new_customer;
       }

       printf("RECORD INSERTED\n");
 }

void print_list(void);

void print_list(void){
    customer *print;

    for (print=database; print != NULL; print = print->next){
    printf("%s\n%s\n%s, %2s %5s\n%9.2f\n-----\n", print->full_name, print->street, print->city, print->state, print->zip, print->account_balance);
    }
}

Upvotes: 0

Views: 66

Answers (1)

John Bollinger
John Bollinger

Reputation: 180073

Your struct does not allow enough space for string terminators. The state field needs a capacity of at least 3 (two characters plus a terminator), and the zip field needs a capacity of at least 6. You might or might not want larger capacity for the other fields.

When you read into the existing struct, you overrun the boundaries of some of the member arrays, producing undefined behavior. The actual output suggests that the terminator of your state string is being overwritten by the first character of the zip, but that's a post hoc analysis -- you cannot assume that it would work that way in all cases.

Upvotes: 1

Related Questions