Thread: Read integers from a file

  1. #1
    Registered User
    Join Date
    Nov 2016
    Posts
    5

    Read integers from a file

    Hello,
    I am trying to read integer from a .txt file and then store the integers in the allocated array using malloc(). My thought is as following:
    Code:
    int *read_text(char *fp, int *size); FILE *fp; fp=fopen("/Users/HughNguyen/Google Drive/Notability/CSCI 2021 Lab/Project1/data/short.txt", "r"); char* array; int i, count = 0; array = malloc(len*sizeof(char)); if (fp == NULL){ size = -1; return NULL; } else{ while(!feof(fp)){ fscanf(file, "%d", &array[count]); count++; } } for(i=0; i<count; i++){ printf(" \n a[%d] = %d\n",i,array[i]); } rewind(fp); fclose(fp); return 0;

    Here is my reason:


    • I open the file using fopen() and I go through the file by using fscanf() to count the number of integers in my file. Then I used malloc() to allocate an array of proper size.
    • I want to use rewind() function to go back to the beginning of the file then reads integers into my array. Close the file when I am done reading all ints. I have to return a pointer to the allocated array.
    • The argument "size" in "int *read_text(char *fp, int *size)" indicates a pointer to an integer which is set to the length of the allocated array.I want to set up a condition that if my file cannot be opened using fopen(), then will set my size to -1 and return NULL.
    • This is a part of the whole program. There are three parts: text_main text_main.c read_text.c.

    I have some errors such as:


    • Redefinition of 'fp' with a different type: 'int' vs 'FILE *'
    • Use of undeclared identifier 'size'
    • A parameter list without types is only allowed in a function definition


    How can I navigate these errors?
    Any tip will be greatly appreciated. Thank you!

  2. #2
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    As for your errors, can you explain what these parameters are for?

    > int *read_text(char *fp, int *size);
    Why is the first named fp? That seems to be one problem.
    And why haven't you used size?


    Well, anyway, to read a file of integers, I think the simplest code is something like this:

    Code:
    int *array = malloc( (?) * sizeof(*array));
    
    if (array == NULL) {
       perror("malloc"); // or any other error handling code
       return EXIT_FAILURE;
    }
    
    for (int i = 0; i < count; i++) {
       fscanf(fp, "%d", &array[i]);
    }
    This is nice and simple especially if you're certain that there will be no problems reading the file; in other words, all the text is guaranteed to be representable C integers. Unfortunately, as you can tell from the example, we need to know what to put for the question mark, and that is not as straight forward. The problem is that using fscanf to count integers ahead of time is difficult. One thing standing in your way is the format string itself. At first glance, a format string that suppresses the assignment to the array appears that it might work, so you try something like:
    Code:
    while ( (rv = fscanf(fp, "%*d")) > 0) count++;
    The trouble with this is, fscanf has to succeed at assigning something in order to return successfully (i.e. with a value of at least 1 for 1 match).

    For this reason I think it is much easier to make a guess at the size of the array that you need, and if you know how, embiggen the array as you read.

    Code:
    size_t cap = 15, size = 0;
    void *temp = NULL;
    int *array = malloc(cap * sizeof(*array));
    
    while (fscanf(fp, "%d", &array[size]) == 1) {
       size++;
       if (size == cap) {
          cap *= 2;
          temp = realloc(array, cap * sizeof(*array));
          if (temp == NULL) {
             perror("realloc");
             free(temp);
             return EXIT_FAILURE;
          }
          array = temp;
       }
    }
    Of course, you could just make a really big array and count the size if you don't want to do all of this work.

  3. #3
    Registered User
    Join Date
    Nov 2016
    Posts
    5
    Hello WhiteFlags,
    Thank you for your response. I am happy to explain myself.
    • First, my bad for picking the name. I should have named fp as "fname" as in "file name".
    • I think I did use size as in: char* array = malloc(*size*sizeof(char));
    • How do you put your code in the fashion in your post? It looks so cool!
    • There are certain ways to do this input style, but I need to stick to the this open source project challenge instructions.

    Code:
    int *read_text_deltas(char *fname, int *len){
    
    
    FILE *fname = fopen("text.txt", "r");
    int i, count = 0;
    char* array = malloc(*len*sizeof(char));
    if (fname == NULL){
        len = -1;
        return NULL;
    }
    else{
        while(!feof(fname)){
        fscanf(fname, "%d", &array[count]);
        count++;
        }
    }
    for(i=0; i<count; i++){
        printf(" \n a[%d] = %d\n",i,array[i]);
    }
    rewind(fname);
    fclose(fname);
    return 0;
    }

  4. #4
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    • Ah okay, are you sure that you didn't mean something like this instead?
      Code:
       FILE *fp = fopen(fname, "r");
      That would make the most sense to me, as fname would be the path and file name string, whereas fp is the name of the variable.

      You keep renaming your file variable the same as your string!
    • Okay, well, little things matter. In the original code, there was int *size, and you used len (a non-pointer with the wrong name).
    • I post code in [code][/code] tags like everyone else. If your source has no other formatting, the syntax would be highlighted for you too.


    I'm still uncertain, but you might want to do something like this.
    Code:
    count = *len;
    array = malloc(count * sizeof(*array));
    That is, I want you to save *len to count so that count has a nonzero value. It makes your code work somewhat better, but I think that what I showed, with the gradually growing array, is really what would work and what should pass for the challenge.

    Also, is there a reason you declared the array as a char*? Since we're reading integers with "%d", it's appropriate to use int, not char.

  5. #5
    Registered User
    Join Date
    Nov 2016
    Posts
    5
    So actually, fname will represent for whatever the name of the file I am going to pass in the function fopen() right?
    In my text_main.c, I have:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "deltas.h"
    
    
    int main(int argc, char *argv[]){
      if(argc < 3){
        printf("usage: %s <format> <filename>\n",argv[0]);
        printf(" <format> is one of\n");
        printf(" text : text ints are in the given filename\n");
        printf(" int  : binary ints are in the given filename\n");
        printf(" 4bit : 4bit binary ints are in the given filename\n");
        return 1;
      }
      char *format = argv[1];
      char *fname = argv[2];
    
    
      int data_len = -1;
      int *data_vals = NULL;
      if( strcmp("text", format)==0 ){
        printf("Reading text format\n");
        data_vals = read_text_deltas(fname, &data_len);
      }
      else if( strcmp("int", format)==0 ){
        printf("Reading binary int format\n");
        data_vals = read_int_deltas(fname, &data_len);
      }
      else if( strcmp("4bit", format)==0 ){
        printf("Reading 4bit binary int format\n");
        data_vals = read_4bit_deltas(fname, &data_len);
      }
      else{
        printf("Unknown format '%s'\n",format);
        return 1;
      }
    
    
      printf("data_len: %d\n",data_len);
      printf("%4s %4s\n","#","read");
      for(int i=0; i<data_len; i++){
        printf("%4d %4d\n",i,data_vals[i]);
      }
    
    
      free(data_vals);
      
      return 0;
    }
    I am thinking "fname" may be defined in this file text_main.c. I have never used fopen() before and I am pretty new to C. I saw some posts online showing how to use fopen such as fopen("file.text","r").
    You are correct about my array declaration. I must use int.
    Now, I have narrowed down to 2 errors, thanks to your help:
    Code:
    #include <stdio.h>
    
    
    int *read_text_deltas(char *fname, int *len){
    
    FILE *fp = fopen(fname, "r");
    int i, count = 0;
    count = *len;
    int* array = malloc(count *sizeof(int)); //Implicitly declaring library function 'malloc' with type 'void *(unsigned long)'
    if (fp == NULL){
        len = &(-1); //Cannot take the address of an rvalue of type 'int'
        return NULL;
    }
    else{
        while(!feof(fp)){
        fscanf(fp, "%d", &array[count]);
        count++;
        }
    }
    for(i=0; i<count; i++){
        printf(" \n a[%d] = %d\n",i,array[i]);
    }
    rewind(fp);
    fclose(fp);
    return 0;
    }
    What do these two errors mean to my logics of the program?

  6. #6
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Well they can both be fixed with some minor changes. The first error about implicitly declaring malloc() can be fixed by including the header that malloc() is declared in, stdlib.h.

    The second error is about trying to take the address of a literal constant, something that you can't really do. To have a similar effect, you can do *len = -1;

    However, unfortunately, with this new context that you've posted I have more to say, and it isn't really good news. It concerns what I was unsure about. You cannot use a negative number as an array size, so code like this won't work very well.
    Code:
    count = *len;
    int* array = malloc(count *sizeof(int));
    You're best bet is to go back to my first post in this thread and try to implement one of the ideas.

  7. #7
    Registered User
    Join Date
    Nov 2016
    Posts
    5
    I see.
    Also, how do I check whether my file contains integers?
    Code:
    if (fp == NULL ||(fscanf(fp, "%d",&array[count])!=1) ){
        count = (-1);
        return NULL;

  8. #8
    Registered User
    Join Date
    Jun 2017
    Posts
    157
    Personally I would start again, using the top-down principle where you start with the main function. Focus first on what to do and later on how to do it. Something like that:
    Code:
    int main()
    {
      int *numbers = NULL; // array that will store the numbers from the file
      int num_elems = count_numbers(FILENAME);
      if (num_elems > 0)
      {
        numbers = read_numbers(FILENAME, num_elems);
        print_numbers(numbers, num_elems);
        free(numbers);
      }
      else
      {
        printf("File was empty");
      }
    }
    Next step would be to implement the functions

    1. count_numbers
    2. read_numbers
    3. print_numbers

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. trying to read from file of integers into 2D array
    By Hana Nasser in forum C Programming
    Replies: 3
    Last Post: 09-14-2015, 11:56 PM
  2. C Prog. Read .txt file with strings and integers
    By akosinoah in forum C Programming
    Replies: 7
    Last Post: 11-16-2013, 12:30 PM
  3. read txt file with strings and integers
    By akosinoah in forum C Programming
    Replies: 4
    Last Post: 11-16-2013, 09:08 AM
  4. read unknown integers from text file
    By underlink in forum C Programming
    Replies: 2
    Last Post: 11-10-2009, 10:23 AM
  5. how to read integers from a file( novice )
    By Gorgorath in forum C++ Programming
    Replies: 7
    Last Post: 10-12-2002, 04:25 AM

Tags for this Thread