user3418283
user3418283

Reputation: 1

Reading data from a text file in C?

So I'm pretty new at reading data from a text file in C. I'm used to getting input using scanf or hard coding.

I am trying to learn how to not only read data from a text file but manipulate that data. For example, say a text file called bst.txt had the following information used to perform operations on a binary search tree:

insert 10
insert 13
insert 5
insert 7
insert 20
delete 5
delete 10
....

With that example, I would have the following code:

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

int main()
{ 
  FILE *fptr;
  char *charptr;
  char temp[50];

  fptr = fopen("bst.txt", "r");

  while(fgets(temp, 50, fptr) != NULL)
  {
    charptr = strtok(temp, " ");

    while(charptr != NULL)
    {
      charptr = strtok(NULL, " ");
    }
  }

return 0;
}

I know that within the first while loop strtok() splits each line in the text file and within the second while loop strtok() splits off when the program recognizes a space, which in this case would separate the operations from the integers.

So my main question is, after, for example, the word "insert" is separated from the integer "10", how do I get the program to continue like this:

if(_____ == "insert")
{
  //read integer from input file and call insert function, i.e. insert(10);
}

I need to fill in the blank.

Any help would be greatly appreciated!

Upvotes: 0

Views: 4481

Answers (4)

Emmet
Emmet

Reputation: 6421

If I were doing what you're doing, I would be doing it that way :)

I see a lot of people getting upvoted (not here, I mean on SO generally) for recommending that people use functions like scanf() and strtok() despite the fact that these functions are uniformly considered evil, not just because they're not thread-safe, but because they modify their arguments in ways that are hard to predict, and are a giant pain in the ass to debug.

If you're malloc()ing an input buffer for reading from a file, always make it at least 4kB — that's the smallest page the kernel can give you anyway, so unless you're doing a bazillion stupid little 100-byte malloc()s, you might as well — and don't be afraid to allocate 10x or 100x that if that makes life easy.

So, for these kinds of problems where you're dealing with little text files of input data, here's what you do:

  • malloc() yourself a fine big buffer that's big enough to slurp in the whole file with buckets and buckets of headroom
  • open the file, slurp the whole damn thing in with read(), and close it
  • record how many bytes you read in n_chars (or whatever)
  • do one pass through the buffer and 1) replace all the newlines with NULs and 2) record the start of each line (occurs after a newline!) into successive positions in a lines array (e.g. char **lines; lines=malloc(n_chars*sizeof(char *)): there can't be more lines than bytes!)
  • (optional) as you go, advance your start-of-line pointers to skip leading whitespace
  • (optional) as you go, overwrite trailing whitespace with NULs
  • keep a count of the lines as you go and save it in n_lines
  • remember to free() that buffer when you're done with it

Now, what do you have? You have an array of strings that are the lines of your file (optionally with each line stripped of leading and trailing whitespace) and you can do what the hell you like with it.

So what do you do?

Go through the array of lines one-by-one, like this:

for(i=0; i<n_lines; i++) {
    if( '\0'==*lines[i] || '#' == *lines[i] )
        continue;
    // More code

}

Already you have ignored empty lines and lines that start with a "#". Your config file now has comments!

long n;
int  len;
for(i=0; i<n_lines; i++) {
    if( '\0'==*lines[i] || '#' == *lines[i] )
        continue;
    // More code

    len = strlen("insert");
    if( 0== strncmp(lines[i], "insert", len) ) {
        n = strtol(lines[i]+len+1, &endp, 10);
        // error checking
        tree_insert( (int)n );
        continue;
    }

    len = strlen("delete");
    if( 0== strncmp(lines[i], "delete", len) ) {
        n = strtol(lines[i]+len+1, &endp, 10);
        // error checking
        tree_delete( (int)n );
    }
}

Now, you can probably see 10 ways of making this code better. Me too. How about a struct that contains a keywords and a function pointer to the appropriate tree function?

Other ideas? Knock yourself out!

Upvotes: 1

Rishi Dwivedi
Rishi Dwivedi

Reputation: 928

try this code

int main(){
FILE *fp;
char character[50];
int value;
fptr = fopen("input.txt", "r");

while (fscanf(fp, "%s%d", character, &value) > 0)
{
  if(strcmp(character,"insert")==0){
      insert(value);//call you function which you want value is 10 or change according to file
  }
}
return 0;
}

Upvotes: 0

feihu
feihu

Reputation: 1953

I think the best way to read formatted strings in file is using fscanf, the following example shows how to parse the file. You could store the charptr and value for further operations:

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

int main()
{ 
  FILE *fptr;
  char charptr[50];
  int value;

  fptr = fopen("bst.txt", "r");

  while (fscanf(fptr, "%s%d", charptr, &value) > 0)
  {
      printf("%s: %d\n", charptr, value);
  }

  return 0;
}

Upvotes: 0

Jayesh Bhoi
Jayesh Bhoi

Reputation: 25885

you can call as follows.For example i have put printf but you can replace your insert/delete function instead that.

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

int main()
{ 
  FILE *fptr;
  char *charptr;
  char temp[50];

  fptr = fopen("bst.txt", "r");

  while(fgets(temp, 50, fptr) != NULL)
  {
    charptr = strtok(temp, " ");

    if(strcmp(charptr,"insert")==0)
    {
      charptr = strtok(NULL, " ");

      printf("insert num %d\n",atoi(charptr));
    }
    else if(strcmp(charptr,"delete")==0)
    {
      charptr = strtok(NULL, " ");

      printf("delete num %d\n",atoi(charptr));
    }
  }

return 0;
}

Upvotes: 0

Related Questions