4

Say I have a text file like this:

User: John

Device: 12345

Date: 12/12/12

EDIT:

I have my code to successfully search for a word, and display the info after that word. However when I try to edit the code to search for 2 or 3 words and display the info after them instead of just 1 word, I cannot get it to work. I have tried adding codes into the same while loop, and creating a new while loop for the other word, but both doesn't work. There must be something I am doing wrong/not doing.

Please advice, thanks!

Here is my code:

 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 int main() {

char file[100];
char c[100];

printf ("Enter file name and directory:");
scanf ("%s",file);

    FILE * fs = fopen (file, "r") ;
    if ( fs == NULL )
    {
           puts ( "Cannot open source file" ) ;
           exit( 1 ) ;
    }

    FILE * ft = fopen ( "book5.txt", "w" ) ;
    if ( ft == NULL )
    {
           puts ( "Cannot open target file" ) ;
           exit( 1 ) ;
    }

while(!feof(fs)) {
   char *Data;
   char *Device;
   char const * rc = fgets(c, 99, fs);

   if(rc==NULL) { break; }

   if((Data = strstr(rc, "Date:"))!= NULL)
   printf(Data+5);

   if((Data = strstr(rc, "Device:"))!=NULL)
   printf(Device+6);
   }



    fclose ( fs ) ;
    fclose ( ft ) ;

return 0;

 }
eddie
  • 1,252
  • 3
  • 15
  • 20
Dave Wang
  • 109
  • 4
  • 12

8 Answers8

1

My suggestion is to use fread to read all the file.You could read it character by character, but IMHO (a personal taste here) it's simpler to get a string containing all the characters and then manipulating it.

This is the function prototype:

size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );

It returns the number of elements read.

For example:

char buffer[100];
size_t n= fread(buffer, 1,100, fs);  

Then you can manipulate the string and divide it in tokens.

EDIT

There is a nice reference with also an example of how dividing a string into tokens here:

http://www.cplusplus.com/reference/cstring/strtok/

Ramy Al Zuhouri
  • 21,580
  • 26
  • 105
  • 187
  • Thank you, i have fixed and added this part to my code. With out the searching for word part, the code compiles and does what it's supposed to do. Would you recommend a command i could use to search for a word from the text file and display the info after it? Thanks a lot! – Dave Wang Dec 27 '12 at 23:02
  • Yes, I would recommend strtok(), I edited the post to add also the reference. – Ramy Al Zuhouri Dec 27 '12 at 23:45
1

fgetc returns an integer value, which is character, promoted to int. I suppose you meant fgets which reads a whole line, but you need to reserve memory for it, for example:

#define BUF 100
...
char c[BUF];
fgets(c, BUF, fs);

Some helpful links.

Frederic Blase
  • 510
  • 1
  • 4
  • 15
1

There are a couple of problems in your code: basically it never compiled.

Here is a version with small cleanups - which at least compiles:

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

int main() {
    char file[100];
    char c[100];

    printf ("Enter file name and directory:");
    scanf ("%s",file);

    FILE * fs = fopen (file, "r") ;
    if ( fs == NULL ) {
       puts( "Cannot open source file" ) ;
       exit(1 ) ;
    }

    while(!feof(fs)) {
       char *Data;
       char const * rc = fgets(c, 99, fs);
       if(rc==NULL) { break; }
       if((Data = strstr(rc, "Device"))!= NULL)
       printf("%s", Data);
    }

    fclose ( fs ) ;

    return 0;
 }

Problems I found:

  • Missing include for exit()
  • Missing parameter for exit()
  • Missing while loop to run through the whole input file.
  • The output file was never used.
  • Missing return value of 'main'
  • Fancy Data[5]
  • Changed fgetc() to fgets()

I only did minimal edits - it's not perfect at all....

IMHO I would go for C++: many things are much simpler there.

Andreas Florath
  • 4,418
  • 22
  • 32
  • Thank you very much taking time to fix my sloppy code. I am fairly new and is still trying to learn C in more details. Your code works great. I can proceed to my next task now. Just a couple of questions tho about your code, I understand that adding a * makes the command a pointer, is that correct? And what is "rc" for? I see that you declared c to be a 100 bit long char? is this c and rc related at all or no? THanks! – Dave Wang Dec 27 '12 at 23:11
  • I answered as answer because my explanation was too big for a comment. – Afonso Tsukamoto Dec 27 '12 at 23:40
1

If printf() isn't a hard/fast rule, and the input requirements are really this simple, I'd prefer a state-machine and a constant-memory input:

int c, x = 0;                              // c is character, x is state
while(EOF!=(c=getchar())){                 // scanner entry point
  if(c == '\n') x=0;                       // newline resets scanner
  else if(x == -1) continue;               // -1 is invalid state
  else if (x < 7 && c=="Device:"[x])x++;   // advance state
  else if (x == 7 && isspace(c)) continue; // skip leading/trailing whitespace
  else if (x == 7) putchar(c);             // successful terminator (exits at \n)
  else x = -1;                             // otherwise move to invalid state
}
geocar
  • 9,085
  • 1
  • 29
  • 37
1

I would do that with two loops: one to get a line from the file and other to make tokens from the line read.

something like:

#define BUFFSIZE 1024
int main()....

char buff[BUFFSIZE];
char delims[] = " ";
char *result = NULL;
int stop = 0;

fp = fopen("yourFile", "r");

while( fgets(buff, BUFFSIZE,fp) != NULL )  /*This returns null when the file is over*/
{
 result = strtok( buff, delims );   /*You just need to do reference to buff here, after this, strtok uses delims to know where to do the next token*/

   while(result != NULL){   /*Strtok returns null when finishes reading the given string*/
      if(strcmp(result,"Device")==0){   /*strcmp returns 0 if the strings are equal*/
         stop = 1;  /*Update the flag*/
         break;     /*Is now possible to break the loop*/
      }
      result = strtok(NULL,delims);  /*Get the next token*/
   }
   if(stop == 1) break; /*This uses the inside flag to stop the outer loop*/
}


result = strtok(NULL, delims); /*Result, now, has the string you want: 12345 */

...

this code is not very accurate and I didn't tested it, but thats how I would try to do it.

Hope this helps.

Afonso Tsukamoto
  • 1,184
  • 1
  • 12
  • 21
  • Thank you very much, i fixed my code a bit and now it works. But i do have one more question, i am trying to get it to search and display more than 1 words now, say i want it to display the info after both "device" and "date", how would i go about doing that? I have tried adding the info in the same while loop, or creating a new while loop, both did not work.. thanks – Dave Wang Dec 27 '12 at 23:22
  • According this your original code here, the first time (result = strtok(NULL,delims);) is used, which was inside of the "if", sets result to "Device" correct? and the 2nd time it was used which is outside of the outer loop sets it to "12345", is that correct? – Dave Wang Dec 28 '12 at 19:27
  • 1
    No, strtok is used inside the seconde loop, but outside the if statement. It breaks the inner loop the first time result finds Device[ if(strcmp(result,"Device")==0)], and the outer strtok(outer as out of both loops) to get the 12345 string. So,what your saying is not entirely wrong, it ends up doing that, but does more iterations to get to that. – Afonso Tsukamoto Dec 28 '12 at 20:15
  • SO if i was to add another value to compare with, should i make another if statement with-in the inner while loop? Because i tried having another (result = strtok(NULL,delims);) inside of the inner while loop, thinking that it would just jump to the next value, but it doesn't do anything.. – Dave Wang Dec 28 '12 at 21:38
  • I guess my question was, if the only time "result" has the value i am looking for is when it is outside of the outer while loop, then how will i be able to get the value i want, and store it into somewhere while inside of the while loops? – Dave Wang Dec 28 '12 at 21:51
  • That is not the case. The code that I made is trying to do that: Only the strtok outside the outer loop is giving you what you want. To make it work for more cases you need to change more one or two things. I told you what you should do in an answer, that one I couldn't fit in the comment area. Anyway, in oreder to get all the values you want from the file, your strtok needs to be done inside some condition so you know what you're getting. In this case, the strtok outside the outer loop is not necessary. Ill try to explain it in a new answer. – Afonso Tsukamoto Dec 28 '12 at 22:01
1

Ok, hope I can clear it this time. Sorry if I get confusing sometimes but my english is not the best.

I'll explain the implementation inside comments:

#define BUFFSIZE 1024
int main()....

char buff[BUFFSIZE];
char delims[] = " ";  /*Where your strtok will split the string*/
char *result = NULL;
char *device; /*To save your device - in your example: 12345*/
char *date; /*To save the date*/
int stop = 0;

fp = fopen("yourFile", "r");

while( fgets(buff, BUFFSIZE,fp) != NULL )  /*This returns null when the file is over*/
{
 result = strtok( buff, delims );   /*You just need to do reference to buff here, after this, strtok uses delims to know where to do the next token*/

   while(result != NULL){   /*Strtok returns null when finishes reading the given string*/
      if(strcmp(result,"Device")==0){   /*strcmp returns 0 if the strings are equal*/
         result = strtok(NULL, delims); /*this one gets the 12345*/
         device = (char*)malloc((strlen(result)+1)*sizeof(char)); /*Alocate the right amount of memory for the variable device*/
         strcpy(device, result); /*Now, device is "12345"*/
      }
       /*Here you do the same but for the string 'Date'*/
       if(strcmp(result,"Date")==0){   /*strcmp returns 0 if the strings are equal*/
         result = strtok(NULL, delims); /*this one gets the 12345*/
         date = (char*)malloc((strlen(result)+1)*sizeof(char)); /*Alocate the right amount of memory for the variable device*/
         strcpy(date, result); /*Now, device is "12/12/12"*/
      }
      /*And you can repeat the if statement for every string you're looking for*/
      result = strtok(NULL,delims);  /*Get the next token*/
   }
}

/*No strtok necessary here */

...

Hope this helps.

Afonso Tsukamoto
  • 1,184
  • 1
  • 12
  • 21
  • It works great now! Thanks! Looks like the part i was missing was that i have to declare the size of the destination string before copying to it (i guess that is always the case when using c?). Thank you very much for your help. I really learned a lot from this. – Dave Wang Dec 28 '12 at 22:29
  • Quick question, what is the (result = strtok(NULL,delims);) at the end of the codes for? Why does it need to get the next token if the values i want is already stored in "date" and "device"? – Dave Wang Dec 28 '12 at 22:30
  • 1
    Anytime. I'm getting addicted to stack overflow because of this: collective learning. And yes, in C, if you want to store you need space for it. Is you want to point you just need a pointer. Good luck! – Afonso Tsukamoto Dec 28 '12 at 22:31
  • The one after the if statements? That one is for result getting the next tok. It increases result like a pointer to the string. If this one wasn't there you wouldn't be able to get the next token from the buff string. – Afonso Tsukamoto Dec 28 '12 at 22:33
  • Btw, if this solved your question, mark the thread as resolved. It helps the guys from stack overflow and my SO Reputation :) – Afonso Tsukamoto Dec 28 '12 at 22:35
  • Got it. Will do! Last question, i am now trying to output the values into the file "book5.txt", how can i make it display (12345,12/12/12)? im trying to use printf(device,",", date) but it gives me an error, is there another command to use for this? – Dave Wang Dec 28 '12 at 22:40
  • You're thinking about two things from java like(or php like). String concatenation in C is not possible with operators. Something that you would do in java like: String a =device+","+date;(Or php: $str=$device.",".$date;) is not possible. You have strcat from string.h library but for what you want to do is not necessary. Use fprintf(http://pubs.opengroup.org/onlinepubs/009695399/functions/printf.html) In this case, what you want is fprintf(YourFilePointer,"%s,%s",device,date); Printf is the standard function for stdout(usually terminal) – Afonso Tsukamoto Dec 28 '12 at 22:46
  • To mark a post as solved, you need to choose the answer to your problem and under the up/down arrows for vote, should appear an right symbol(V letter like). Press it and thats it. You can have more than one answer, I guess. – Afonso Tsukamoto Dec 28 '12 at 22:51
  • (fprintf (ft, "%s,%s", device, date); ) gives me: 12345 ,12/12/12 is there a way to make it so that its all in one line? (12345,12/12/12) – Dave Wang Dec 28 '12 at 22:55
  • That's because you're strtok is saving the new line character(/n). You need to 'clean' your string. For that, you can simply assume that the character is in the end of the string(not safe) or do a loop trying to find it. For example: for(i=0;i – Afonso Tsukamoto Dec 28 '12 at 23:00
  • but there is no /n anywhere in my code(?) how can i make it save just the word and not the new line character? – Dave Wang Dec 28 '12 at 23:03
  • 1
    And that \n character doesn't need to be on your code, it is read from the file from strtok and saved on your variable. – Afonso Tsukamoto Dec 28 '12 at 23:06
  • Oh! I find a mistake.Is not device[i] = ' '; but with double quotes: device[i] = " "; – Afonso Tsukamoto Dec 28 '12 at 23:07
  • Glad to know. Good luck! – Afonso Tsukamoto Dec 28 '12 at 23:12
  • hmm it says "Pointer implicitly converted to integral value in assignment." when i use device[i]=" "; – Dave Wang Dec 28 '12 at 23:14
  • i just used device[i]=','; or device[i]=' '; instead, which i guess just fills up that last space – Dave Wang Dec 28 '12 at 23:16
  • Ok,my fix was wrong, it is, in fact, device[i]=' '; cause its a char. Sorry for the confusion. – Afonso Tsukamoto Dec 28 '12 at 23:18
  • Do you know of a way for it to search for "Device****" with those **** as don't cares? – Dave Wang Dec 29 '12 at 00:18
  • If you have an 'separator' between the 'device' and the 'dont cares', you can easily find it with another strtok. Without that, all I can think of is looping through the string till you get to where you want. – Afonso Tsukamoto Dec 29 '12 at 12:44
0

c and Data are char-pointers, pointers to (the start of a list of) character value(s).

fgetc's prototype is int fgetc ( FILE * stream ); meaning that it returns (one) integer value (an integer is convertible to a single char value).

If fgetc's prototype would've been int * fgetc ( FILE * stream ); the warning wouldn't have appeared.

Mihai Stancu
  • 15,848
  • 2
  • 33
  • 51
0

@Dave Wang My answer was too big to be a comment. So here it goes:

You're welcome. Glad to help.

If you make a new loop, the fgets won't work because you are already 'down' in the text file. Imagine something like a pointer to the file, every time you 'fget it' from a file pointer, you advance that pointer. You have functions to reload the file or push that pointer up, but it is not efficient, you've already passed by the information you want, there must be a way to know when.

If you're using my implementation, that is done by using another string compare inside the loop: if(strcmp(result,"date") == 0) If you enter this if, you know that the next value in result token with strtok is the actual date. Since you have now two conditions to be tested, you can't break the outer loop before having both of them. This can be accomplished by two ways:

1-Instead of a flag, use a counter that is incremented everytime you want an information. If that counter has the same number of information you want, you can break the outer loop.

2-Don't break the outer loop at all! :)

But in both, since there are 2 conditions, make sure you treat them inside the ifs so you know that you dealing with the right information.

Hope this helps. Anything, just ask.

Afonso Tsukamoto
  • 1,184
  • 1
  • 12
  • 21