-1

I am trying to read numbers from a file and put those numbers into an array. And now the file looks like this:

100

0 1 2 3 4 5 6 7 8 9

10 11 12 13 14 15 16 17 18 19

20 21 22 23 24 25 26 27 28 29

Obviously the first number is the size of the array. While I try to test the read, I got 8. And here's my code:

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

int main()
{
    FILE * filePtr;
    int firstNum;
    filePtr = fopen("array,dat", "r");
    if(filePtr!=NULL)
    {
    fscanf(filePtr, "%d", &firstNum);
    fclose(filePtr);
    }
    printf("size: %d", firstNum);


    return 0;
}

and this is the result I got:

size: 8
Process returned 0 (0x0)   execution time : 0.012 s
Press any key to continue.

So how can I get the correct number that I want and why does it show 8?

  • 4
    Typo: `"array,dat"` should be `"array.dat"` – David Ranieri Oct 13 '15 at 06:29
  • 3
    How do you know the file actually opened and `firstNum` is not simply uninitialized? `array,dat` looks suspicious. – Andon M. Coleman Oct 13 '15 at 06:29
  • Since you are reading lines *line-oriented-input* is better for your job. Read a line at a time (`fgets` or `getline`) into a buffer, then use `strtol` to walk down each line separating numbers into the array. You could use `strtok` or `strsep` to separate the values in each line, but why? You still have to do numerical conversion. So you might as well just use `strtol` and do the separation and conversion all in one call. Look at the declaration for `strtol (char *ptr, char **endptr, int base);` after conversion, endptr will point to the next char after the number you just converted. – David C. Rankin Oct 13 '15 at 06:32
  • Thank you guys! :) I didn't realize I typed the wrong file name. After I fixed it, it worked. But the strok or strsep will be a good idea for me, it may save a lot of works. –  Oct 13 '15 at 06:38
  • @WhiteJade You could have avoided that. First: always initialize your variables. In this case e.g. `int firstNum = 0;` In that case. No misleading 8 then. Second: output the size inside the `if`-Block. Then you would not have gotten the misleading output. Third: Check for the error case first, before you continue with the successful case. Let your `if`-Statement read `if(filePtr!=NULL)`. Then output some error message and return. Read from the file after the `if`-Block then. All these measures don't keep you from mistyping your file name, but they support you to find the issue on your own. – cdonat Oct 13 '15 at 07:45
  • Since this was a typo, I recommend you remove the question, It's not very helpful – gmelodie Sep 23 '18 at 15:23

4 Answers4

4

Because of a typo array,dat -> array.dat, your program fails to open the file. So it will then merely print the contents of the uninitialized variable firstNum, which may contain any garbage value.

It would be better if you wrote your error handling like for example:

if(filePtr==NULL)
{
  printf("Could not open file %s", fileName);
  return 0; // no point in continuing execution after this
}
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 1
    Printing errors to the standard output is not a good idea, use `perror("fopen");` – David Ranieri Oct 13 '15 at 06:37
  • @AlterMann Who, except the user cares? If you communicate the error to the user, all is well. There's no point in specializing in all the dirty details of C streams, since modern programming involves GUI, not console junk. – Lundin Oct 13 '15 at 06:42
  • 1
    It can be a problem when you want to redirect the result `./app > db.dat` – David Ranieri Oct 13 '15 at 06:49
0

Try this one

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

int main()
{

FILE *myFile;
myFile = fopen("array.dat", "r");

//read file into array
int numberArray[100];
int i;

if (myFile == NULL)
{
    printf("Error Reading File\n");
    exit (0);
}else
{
for (i = 0; i < (sizeof( numberArray ) / sizeof( numberArray[0] )); i++)
{
    fscanf(myFile, "%d,", &numberArray[i] );

}

for (i = 0; i <  (sizeof( numberArray ) / sizeof( numberArray[0] )); i++)
{
       printf("Number is: %d\n\n", numberArray[i]);
}
}
fclose(myFile);

return 0;
}
Abdul Manaf
  • 4,933
  • 8
  • 51
  • 95
0

There are many ways to approach this task. The key is making it work regardless of small variations in input format. That is where strtol excels. It also provides much better error analysis on a conversion failure than most.

The example below simply reads your data into an array by reading a line-at-a-time and parsing that line into values with strtol. Take a look and give it a try. Note the functions below dealing with allocating memory are just to keep the body of the code clean so you can hopefully follow the logic easier without all the allocation validation checks filling up main(). Good luck:

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

#define ROWS 3
#define COLS 3
#define MAXC 256

long xstrtol (char *p, char **ep, int base);
void *xcalloc (size_t n, size_t s);
void *xrealloc_sp (void *p, size_t sz, size_t *n);
void *xrealloc_dp (void **p, size_t *n);

int main (void) {

    char line[MAXC] = {0};              /* line buffer for fgets    */
    char *p, *ep;                       /* pointers for strtol      */
    int **array = NULL;                 /* array of values          */
    size_t row = 0, col = 0, nrows = 0; /* indexes, number of rows  */
    size_t rmax = ROWS, cmax = COLS;    /* row/col allocation size  */

    /* allocate ROWS number of pointers to array of int */
    array = xcalloc (ROWS, sizeof *array);

    /* read each line in file */
    while (fgets(line, MAXC, stdin))
    {
        p = ep = line;  /* initize pointer/end pointer      */
        col = 1;        /* start col at 1, store ncols in 0 */
        cmax = COLS;    /* reset cmax for each row          */

        /* allocate COLS number of int for each row */
        array[row] = xcalloc (COLS, sizeof **array);

        /* convert each string of digits to number */
        while (errno == 0)
        {
            array[row][col++] = (int)xstrtol (p, &ep, 10);

            if (col == cmax) /* if cmax reached, realloc array[row] */
                array[row] = xrealloc_sp (array[row], sizeof *array[row], &cmax);

            /* skip delimiters/move pointer to next digit */
            while (*ep && *ep != '-' && (*ep < '0' || *ep > '9')) ep++;
            if (*ep)
                p = ep;
            else  /* break if end of string */
                break;
        }
        array[row++][0] = col; /* store ncols in array[row][0] */

        /* realloc rows if needed */
        if (row == rmax) array = xrealloc_dp ((void **)array, &rmax);
    }
    nrows = row;  /* set nrows to final number of rows */

    printf ("\n the simulated 2D array elements are:\n\n");
    for (row = 0; row < nrows; row++) {
        for (col = 1; col < (size_t)array[row][0]; col++)
            printf ("  %4d", array[row][col]);
        putchar ('\n');
    }
    putchar ('\n');

    /* free all allocated memory */
    for (row = 0; row < nrows; row++)
        free (array[row]);
    free (array);

    return 0;
}

/** a simple strtol implementation with error checking.
 *  any failed conversion will cause program exit. Adjust
 *  response to failed conversion as required.
 */
long xstrtol (char *p, char **ep, int base)
{
    errno = 0;

    long tmp = strtol (p, ep, base);

    /* Check for various possible errors */
    if ((errno == ERANGE && (tmp == LONG_MIN || tmp == LONG_MAX)) ||
        (errno != 0 && tmp == 0)) {
        perror ("strtol");
        exit (EXIT_FAILURE);
    }

    if (*ep == p) {
        fprintf (stderr, "No digits were found\n");
        exit (EXIT_FAILURE);
    }

    return tmp;
}

/** xcalloc allocates memory using calloc and validates the return.
 *  xcalloc allocates memory and reports an error if the value is
 *  null, returning a memory address only if the value is nonzero
 *  freeing the caller of validating within the body of code.
 */
void *xcalloc (size_t n, size_t s)
{
    register void *memptr = calloc (n, s);
    if (memptr == 0)
    {
        fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
        exit (EXIT_FAILURE);
    }

    return memptr;
}

/** reallocate array of type size 'sz', to 2 * 'n'.
 *  accepts any pointer p, with current allocation 'n',
 *  with the type size 'sz' and reallocates memory to
 *  2 * 'n', updating the value of 'n' and returning a
 *  pointer to the newly allocated block of memory on
 *  success, exits otherwise. all new memory is
 *  initialized to '0' with memset.
 */
void *xrealloc_sp (void *p, size_t sz, size_t *n)
{
    void *tmp = realloc (p, 2 * *n * sz);
#ifdef DEBUG
    printf ("\n  reallocating '%zu' to '%zu', size '%zu'\n", *n, *n * 2, sz);
#endif
    if (!tmp) {
        fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
        exit (EXIT_FAILURE);
    }
    p = tmp;
    memset (p + *n * sz, 0, *n * sz); /* zero new memory */
    *n *= 2;

    return p;
}

/** reallocate memory for array of pointers to 2 * 'n'.
 *  accepts any pointer 'p', with current allocation of,
 *  'n' pointers and reallocates to 2 * 'n' pointers
 *  intializing the new pointers to NULL and returning
 *  a pointer to the newly allocated block of memory on
 *  success, exits otherwise.
 */
void *xrealloc_dp (void **p, size_t *n)
{
    void *tmp = realloc (p, 2 * *n * sizeof tmp);
#ifdef DEBUG
    printf ("\n  reallocating %zu to %zu\n", *n, *n * 2);
#endif
    if (!tmp) {
        fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
        exit (EXIT_FAILURE);
    }
    p = tmp;
    memset (p + *n, 0, *n * sizeof tmp); /* set new pointers NULL */
    *n *= 2;

    return p;
}

Compile

gcc -Wall -Wextra -Ofast -o bin/array_ukn_size array_ukn_size.c

Input

$ cat ../dat/10by10.txt
0 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69
70 71 72 73 74 75 76 77 78 79
80 81 82 83 84 85 86 87 88 89
90 91 92 93 94 95 96 97 98 99

Output

$ ./bin/array_ukn_size <../dat/10by10.txt

 the simulated 2D array elements are:

     0     1     2     3     4     5     6     7     8     9
    10    11    12    13    14    15    16    17    18    19
    20    21    22    23    24    25    26    27    28    29
    30    31    32    33    34    35    36    37    38    39
    40    41    42    43    44    45    46    47    48    49
    50    51    52    53    54    55    56    57    58    59
    60    61    62    63    64    65    66    67    68    69
    70    71    72    73    74    75    76    77    78    79
    80    81    82    83    84    85    86    87    88    89
    90    91    92    93    94    95    96    97    98    99
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • Thanks you man! :) The lab actually have some modification on the file, these codes are just my test program. I am just new to C and I think I will have to do a lot of research on it. –  Oct 13 '15 at 07:16
0

For example your input file name is input.txt .Now save this file with your source(.c) file same folder. now you can read input file by this way

freopen("input.txt","r",stdin); 

Here full code

#include <stdio.h>

int main()
{
    int firstNum,otherNum;
    freopen("input.txt","r",stdin);
    scanf("%d",&firstNum);// this read first number 100
    while(scanf("%d",&otherNum)==1)// this loop continue until end of file
    {
         // hear you get other numbers
         printf("%d",otherNum) ; // this line print 0 1 2 3 to 99
    }
    return 0;
}

Note:Use Code::Blocks IDE

Newaz Hossain
  • 157
  • 1
  • 4
  • can you explain what is scanf("%d",&otherNum)==1 doing? I am kind of confuse on this line –  Oct 13 '15 at 17:29
  • Please see this [answer](http://stackoverflow.com/questions/10469643/value-returned-by-scanf-function-in-c) – Newaz Hossain Oct 14 '15 at 05:54