My file contains:

Hook,Mark,In, , ,Tire,Matt,Out,01/01/2001,Mike

My structure:

struct part {
  char name   [NAME_LEN+1];
  char owner  [OWNER_LEN+1];
  char status [STATUS_LEN+1];
  char date   [DATE_LEN+1];
  char renter [RENTER_LEN+1];
} parts [MAX_PARTS], temp [1];

And the code:

FILE *fp;
fp=fopen("parts.csv","r");
printf("%d", fp);                   //Added this for debugging
char buf[100];
int i;
for(i=0; i < MAX_PARTS; i++) {
  while(i<100 && fgets(buf,sizeof(buf),fp) != NULL){
    printf("%s", buf);          //for debugging
    strcpy(parts[i].name, strtok(buf,","));
    strcpy(parts[i].owner, strtok(NULL,","));
    strcpy(parts[i].status, strtok(NULL,","));
    strcpy(parts[i].date, strtok(NULL,","));
    strcpy(parts[i].renter, strtok(NULL,","));
    }
}

In this example, I am trying to save "Hook" into parts[0].name, "Mark" to parts[0].owner, "In" into parts[0].status, and then blank strings in parts[0].date and parts[0].renter. Then i++, so it should save "Tire" into parts[1].name, "Matt" into parts[1].owner, etc. Once the end of the file is reached, the loop should exit and it should continue with whatever code follows it. When I print fp, it is not null so it is opening, and when I print buf, it prints my file contents, so up to that point it is working. But if I try to print parts[0] or part[1] they are both blank. Why is nothing being copied?

Recommended Answers

All 14 Replies

I really don't care to make up the #defines and the rest. Do you suppose you could just post a small, but complete and compilable snippet?
kthxbye

[edit]But the nested loops don't look like a happy thing to do.

I really don't care to make up the #defines and the rest. Do you suppose you could just post a small, but complete and compilable snippet?
kthxbye

[edit]But the nested loops don't look like a happy thing to do.

I will post the whole code, because once I get this part sorted out, I will need to do just the opposite of what I am trying to do now, and write the entire structure back to the file after the user quits. But one thing at a time... The code in question is at the beginning.

And I'm not sure if I could use sscanf(). From what I can tell, I would have to take out the commas from my text file, and separate the values with spaces. That is fine, but if I take the , in this line:

Hook,Matt,in, , ,

I would end up with

Hook Matt in

I used to have 5 values, now I have 3. I need those last two blank strings at the end. Anyway to get sscanf() to recognize white spaces?

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

#define NAME_LEN 25
#define OWNER_LEN 25
#define STATUS_LEN 4
#define DATE_LEN 11
#define RENTER_LEN 25
#define MAX_PARTS 100

int locate_part (char name[]);
void add(void);
void delete(void);
void display(void);
void checkin(void);
void checkout(void);
void reports(void);
void part(void);
void owner(void);
void status(void);

int num_parts = 0;

struct part {
  char name   [NAME_LEN+1];
  char owner  [OWNER_LEN+1];
  char status [STATUS_LEN+1];
  char date   [DATE_LEN+1];
  char renter [RENTER_LEN+1];
} parts [MAX_PARTS], temp [1];

//MAIN

int main(void) {

char choice;

FILE *fp;
fp=fopen("parts.csv","r");
printf("%d", fp);
char buf[100];
int i;
for(i=0; i < MAX_PARTS; i++) {
  while(i<100 && fgets(buf,sizeof(buf),fp) != NULL){
    printf("%s", buf);
    strcpy(parts[i].name, strtok(buf,","));
    strcpy(parts[i].owner, strtok(NULL,","));
    strcpy(parts[i].status, strtok(NULL,","));
    strcpy(parts[i].date, strtok(NULL,","));
    strcpy(parts[i].renter, strtok(NULL,","));
    }
}
for(;;) {
  
  printf("[a]dd part, [d]elete part, dis[p]lay part, check [i]n part, check [o]ut part, [r]eports, [q]uit\n");
  printf("Please enter your choice: ");
  scanf(" %c", &choice);
  
  while (getchar() != '\n');
    
    switch (choice) {
      case 'a' : add();
      break;

      case 'd' : delete();
      break;

      case 'p' : display();
      break;

      case 'i' : checkin();
      break;

      case 'o' : checkout();
      break;

      case 'q' : return 0;

      case 'r' : reports();
      break;
     
      default : printf("Please try again\n");
    }
    printf("\n");
}
}

//LOCATE PART

int locate_part (char name[]) {

  int i;
 
  for (i=0; i < num_parts; i++)
    if (strcmp(parts[i].name, name) == 0)
     return i;
  return -1;
}

//ADD PART

void add (void) {

  char name[20];

  if (num_parts == MAX_PARTS) {                  
    printf("Database is full.\n");
    return;
  }

  printf("Enter part name: ");
  fgets (name, 20, stdin);
  if (name[strlen (name) - 1] == '\n')
      name[strlen (name) - 1] = '\0';                                                      
  
                            
  if (locate_part(name) != -1) {                        
    printf("Part is already in database.\n");         
    return;
  }

  strcpy(parts[num_parts].name, name);                 
  printf("Owners name: ");
  read_line(parts[num_parts].owner, OWNER_LEN);
  strcpy(parts[num_parts].status, "in");
  num_parts++;
}

//DELETE PART

void delete (void) {
  int i;                                
  char pname[20];
  
  printf("Enter part to delete: "); 
  scanf("%s", pname);                       
                                         
  i = locate_part(pname);

  if (i >=0) {
    strcpy(parts[i].name, "");
    strcpy(parts[i].owner, "");
    strcpy(parts[i].status, "");
    strcpy(parts[i].date, "");
    strcpy(parts[i].renter, "");
    
}

for(i=0; i < num_parts - 1; i++)
  if (strcmp(parts[i].name, "") == 0) {
    for(i; i < num_parts -1; i++)
      parts[i]=parts[i+1];
      }
num_parts--;
}


//DISPLAY PART

void display (void) {                        
  int i;                                     
  char pname[20];
  
  printf("Enter part name: "); 
  scanf("%s", pname);                       
                                            
  i = locate_part(pname);

  if (i >=0) {
    printf("\n");
    printf("%s : %s : %s : %s : %s\n", parts[i].name, parts[i].owner, parts[i].status, parts[i].date, parts[i].renter); 
    printf("\n");
  }
  else
  printf("Part not found");
}

//CHECK IN

void checkin (void) {
  int i;                                
  char pname[20];
  char rent[20];
  
  printf("Enter part to checkout: "); 
  scanf("%s", pname);               
   
                                         
  i = locate_part(pname);

  if (i >=0 && (strcmp(parts[i].status, "out")==0)) {
    strcpy(parts[i].status, "in");
    strcpy(parts[i].date, "");
    strcpy(parts[i].renter, "");
    
}else
printf("\nPart is out, or does not exist\n");
}

//CHECK OUT 

void checkout (void) {
  int i;                                
  char pname[20];
  char rent[20];
  time_t current = time(NULL);
  char date[11];

  strftime (date, 11, "%m/%d/%Y", localtime (&current));
  
  printf("Enter part to checkout: "); 
  scanf("%s", pname);               
  printf("Renter's name: ");
  scanf("%s", rent);        
                                         
  i = locate_part(pname);

  if (i >=0 && (strcmp(parts[i].status, "in")==0)) {
    strcpy(parts[i].status, "out");
    strcpy(parts[i].date, date);
    strcpy(parts[i].renter, rent);
    
}else
printf("\nPart not found or part is already out\n");
}

//REPORTS
void reports(void) {

char choice;

for(;;) {
  
  printf("Sort by: [p]art name, [o]wner, [s]tatus, [q]uit \n");
  printf("Please enter your choice: ");
  scanf(" %c", &choice);
  
  while (getchar() != '\n');
    
    switch (choice) {
      case 'p' : part();
      break;

      case 'o' : owner();
      break;

      case 's' : status();
      break;

      case 'q' : return;

      default : printf("Please try again\n");
    }
    printf("\n");
}
}

void part (void){
    int i;
  int n;
  for (n=0; n < num_parts; n++){
  
  for (i=0; i < num_parts-1; i++)
    if (strcmp(parts[i].name, parts[i+1].name) > 0) {
      temp[1]=parts[i];
      parts[i]=parts[i+1];
      parts[i+1]=temp[1];
      
}
printf("\n");
}
    for(i=0; i < num_parts; i++){
    printf("%s:%s:%s", parts[i].name, parts[i].owner, parts[i].status);
     if (strcmp(parts[i].status, "in")==0){ 
      printf("\n");}
     else 
    printf(":%s:%s\n", parts[i].date, parts[i].renter);
}
}
void status (void){

  int i;
  int n;
  for (n=0; n < num_parts; n++){
  
  for (i=0; i < num_parts-1; i++)
    if (strcmp(parts[i].status, parts[i+1].status) > 0) {
      temp[1]=parts[i];
      parts[i]=parts[i+1];
      parts[i+1]=temp[1];
      
}
printf("\n");
}
  for(i=0; i < num_parts; i++){
    printf("%s:%s:%s", parts[i].name, parts[i].owner, parts[i].status);
     if (strcmp(parts[i].status, "in")==0){ 
      printf("\n");}
     else 
    printf(":%s:%s\n", parts[i].date, parts[i].renter);
}
}
void owner (void){
  int i;
  int n;
  for (n=0; n < num_parts; n++){
  
  for (i=0; i < num_parts-1; i++)
    if (strcmp(parts[i].owner, parts[i+1].owner) > 0) {
      temp[1]=parts[i];
      parts[i]=parts[i+1];
      parts[i+1]=temp[1];
      
}
printf("\n");
}
    for(i=0; i < num_parts; i++){
    printf("%s:%s:%s", parts[i].name, parts[i].owner, parts[i].status);
     if (strcmp(parts[i].status, "in")==0){ 
      printf("\n");}
     else 
    printf(":%s:%s\n", parts[i].date, parts[i].renter);
}
}

Thanks for the whole code.

I'm generally not a "parsing with strtok" fan; handling empty fields I've done this way:
http://www.daniweb.com/code/snippet216569.html
http://www.daniweb.com/code/snippet216681.html
http://www.daniweb.com/code/snippet216682.html

Delimiter and other things are different, but it may give you some ideas to try a different way.

In the meantime, I'll take a peek at what you've got.
[edit]Hmm...

main.c
main.c: In function `main':
main.c:43: warning: int format, pointer arg (arg 2)
main.c: In function `add':
main.c:135: warning: implicit declaration of function `read_line'
main.c: In function `delete':
main.c:165: warning: statement with no effect
main.c: In function `checkin':
main.c:200: warning: unused variable `rent'
Linking...
Debug/main.o: In function `add':
C:/Users/Dave/Projects/scratch/main.c:135: undefined reference to `_read_line'
collect2: ld returned 1 exit status
*** Errors occurred during this build ***

:(

I got rid of the nested loops and somehow it just started working. I swear I tried this before, and it didn't work, but now it does. Only problem is, it only works once. parts[0] is filled correctly, but parts[1] is not touched. So if my text file contains what I said above, parts[0] equals "Hook:Mark:In: : " like it should, but parts[1] should be receiving the input "Tire:Matt:Out:01/01/2001:Mike", and parts[2] should be filled with anything that comes after that. I guess there is something funky going on with my loop.

FILE *fp;
fp=fopen("parts.csv","r");

char buf[100];

  while(fgets(buf,sizeof(buf),fp) != NULL){
    strcpy(parts[num_parts].name, strtok(buf,","));
    strcpy(parts[num_parts].owner, strtok(NULL,","));
    strcpy(parts[num_parts].status, strtok(NULL,","));
    strcpy(parts[num_parts].date, strtok(NULL,","));
    strcpy(parts[num_parts].renter, strtok(NULL,","));
    num_parts++;
  }

I'm thinking the empty fields is not working well with strtok. As I've mentioned, I'm not a strtok fan. Are you required to use it?

Thanks for the whole code.

I'm generally not a "parsing with strtok" fan; handling empty fields I've done this way:
http://www.daniweb.com/code/snippet216569.html
http://www.daniweb.com/code/snippet216681.html
http://www.daniweb.com/code/snippet216682.html

Delimiter and other things are different, but it may give you some ideas to try a different way.

In the meantime, I'll take a peek at what you've got.
[edit]Hmm...:(

Funny... It compiles cleanly on my school's linux box. I didn't include my readline.c and readline.h files so that's one reason it won't compile for you, but the rest of the errors I don't understand. Anyway, they all occur outside of this problem code so here is the snippet you originally requested. This code for me prints:

Hook:Mark:In: :
::::

and I think strtok is working with the white spaces, because it prints as it should (above) and even If I edit the file and fill those blanks in, I still get the same result. parts[1] is not getting touched.

EDIT: I Just realized, on the second iteration of the while loop (if this is even happening) should not start with

strcpy(parts[num_parts].name, strtok(buf,","))

but rather

strcpy(parts[num_parts].name, strtok(NULL,","))

right? Because I want it to pick up where it left of on the last strtok() call.

I am not required to use strtok(), but I am so close to getting it to work, I'd rather not try something else, unless it is necessary.

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

#define NAME_LEN 25
#define OWNER_LEN 25
#define STATUS_LEN 4
#define DATE_LEN 11
#define RENTER_LEN 25
#define MAX_PARTS 100

int num_parts = 0;

struct part {
  char name   [NAME_LEN+1];
  char owner  [OWNER_LEN+1];
  char status [STATUS_LEN+1];
  char date   [DATE_LEN+1];
  char renter [RENTER_LEN+1];
} parts [MAX_PARTS], temp [1];

//MAIN

int main(void) {

int i;
char choice;

FILE *fp;
fp=fopen("parts.csv","r");

char buf[100];

  while(fgets(buf,sizeof(buf),fp) != NULL){
    strcpy(parts[num_parts].name, strtok(buf,","));
    strcpy(parts[num_parts].owner, strtok(NULL,","));
    strcpy(parts[num_parts].status, strtok(NULL,","));
    strcpy(parts[num_parts].date, strtok(NULL,","));
    strcpy(parts[num_parts].renter, strtok(NULL,","));
    num_parts++;
  }
for(i=0; i <= num_parts; i++)
    printf("%s:%s:%s:%s:%s\n", parts[i].name, parts[i].owner, parts[i].status, parts[i].date, parts[i].renter);

}

I've been off my game tonight and subpar with my attempts to help (as I mentioned in another thread as well.

I had muffed the input data for one thing.

I've been off my game tonight and subpar with my attempts to help (as I mentioned in another thread as well.

I had muffed the input data for one thing.

No Problem. Although I would love to get this done soon, I'm in no hurry. If you want to take a look at it later, it would be greatly appreciated. But would fixing what I said about the second iteration of the while loop fix anything? Or if the second iteration even occurring? I think my mistake is either in the while loop conditions, or what I said about changing "buf" to "NULL" the second iteration. I would test this, but I don't know how to write the loop. Maybe a do while loop??

Bleh. I need to call it a night and leave better advice to others.

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

#define NAME_LEN 25
#define OWNER_LEN 25
#define STATUS_LEN 4
#define DATE_LEN 11
#define RENTER_LEN 25
#define MAX_PARTS 100

struct part
{
   char name   [NAME_LEN+1];
   char owner  [OWNER_LEN+1];
   char status [STATUS_LEN+1];
   char date   [DATE_LEN+1];
   char renter [RENTER_LEN+1];
} parts [MAX_PARTS];

int main(void)
{
   int i = 0, j;
   char buf[100];
   FILE *fp = fopen("parts.csv","r");
   if ( !fp )
   {
      perror("parts.csv");
   }
   while ( fgets(buf,sizeof(buf),fp) != NULL )
   {
      char *ptr = buf;
      while ( ptr )
      {
         ptr = strtok(ptr,",");
         if ( ptr )
         {
            strcpy(parts[i].name, ptr);
         }
         ptr = strtok(NULL,",");
         if ( ptr )
         {
            strcpy(parts[i].owner, ptr);
         }
         ptr = strtok(NULL,",");
         if ( ptr )
         {
            strcpy(parts[i].status, ptr);
         }
         ptr = strtok(NULL,",");
         if ( ptr )
         {
            strcpy(parts[i].date, ptr);
         }
         ptr = strtok(NULL,",");
         if ( ptr )
         {
            strcpy(parts[i].renter, ptr);
         }
         if ( ptr )
         {
            i++;
            ptr += 2;
         }
      }
      for ( j = i, i = 0; i < j; ++i )
      {
         printf("%s:%s:%s:%s:%s\n", parts[i].name, parts[i].owner,
                parts[i].status, parts[i].date, parts[i].renter);
      }
   }
   return 0;
}

/* parts.csv
Hook,Mark,In, , ,Tire,Matt,Out,01/01/2001,Mike
*/

/* my output
Hook:Mark:In: : 
Tire:Matt:Out:01/01/2001:Mike
*/

Why I did the pointer increment by two, I'm not entirely sure.

Are all lines containing two records, rather than one record per line?

commented: Thank you for typing all of that up, but all I had to do was put the records on serperate lines. +1

Are all lines containing two records, rather than one record per line?

I guess I should have mentioned this... It doesn't really matter how the file is formatted...

Now that I have put each record on a new line, the original code works! Can you explain why it works now and it wouldn't before? It works when text file looks like this:

Hook,Mark,In, , ,
Tire,Matt,Out,01/01/2001,Mike,
Door,Tim,In, , ,

but not when it's all in the same line.

I guess I should have mentioned this... It doesn't really matter how the file is formatted...

Well, it matters to the parsing. Different formats require different things in the parse. As this exercise kinda shows.

Now I am trying to write the structure back to the file. This works, but the problem is when it prints it is not including the blank spaces. It looks like:

Hook,Mark,In,,

when it should look like this:

Hook,Mark,In, ,

Any idea how to get the spaces to print too?

void writedata(void)
{
   FILE* fp = 0;
   char* buffer = 0;
   int i;
   

   buffer = malloc ( 500 );
   bzero( buffer, 500 );
   fp = fopen( "parts.csv", "w" );

for(i=0; i < num_parts; i++) {
   snprintf( buffer, 500,
      "%s,%s,%s,%s,%s,\n", 
      parts[i].name, parts[i].owner, parts[i].status, parts[i].date, parts[i].renter );
   

   
   fputs( buffer, fp );
   }
   free( buffer );
   
   fclose( fp );
}

EDIT: Never mind, figured it out. Thanks for all the help! I need to do one more check, but I think I am finally done with this project.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.