简体   繁体   中英

Parsing a text file of integers into an array

I'm using strtok() to parse each integer and place it into int nums[1000] . The file will always follow the format of:

the first line has the numbers for the array, each separated by spaces. No more than 10 numbers will be on the line. Nothing is in the file after the first line.

printf("Starting program\n");
char file_name[100];
strcpy(file_name, args[1]);
char number[100];
strcpy(number, args[2]);
FILE *fp;
fp = fopen(file_name, "r");
if (fp == NULL) {
    printf("Error opening file\n");
}
char int_array[1000];//
int nums[1000]; //storing the integers without spaces
int i = 0; //for indexing the array to save the integers
while (fgets(int_array, 1000, fp) != NULL) {
    printf("%s\n", "test");
    puts(int_array); // prints out `1 2 3 4 5...`
    char *token;
    token = strtok(int_array, " ");
    nums[i] = atoi(token);
    while (token != NULL) {
        token = strtok(NULL, " ");
        nums[i] = atoi(token);
        //puts(token); Token gets printed out correctly.
    }
}

printf("%i\n", nums[i]); // this gives segmentation fault
printf(nums) // also gives seg fault

I cannot figure out why I am getting seg fault.

There are multiple problems in your code, the main issue is you test token before scanning the next token:

while (token != NULL) {
    token = strtok(NULL, " ");
    nums[i] = atoi(token);
}

You should instead do this:

while ((token = strtok(NULL, " ")) != NULL) {
    nums[i] = atoi(token);
}

Other issues:

  • You do not check if argc > 1 before accessing argv[1] in strcpy(file_name, args[1]); , potentially invoking undefined behavior.
  • You copy the file name into a 100 byte array: if the command line argument is longer than 99 bytes, you are causing a buffer overflow. You do not need to copy the argument, just pass argv[1] to fopen or use a pointer: char *filename = argv[1];
  • You check if fopen() failed, but do not exit the function... fgets() has undefined behavior for a null stream pointer.
  • strtok() can return NULL even for the first call. Always check the return value before passing it to atoi() .
  • You do not check if i becomes too large. You should stop reading the input file if i reaches 1000 .
  • Passing the nums array to printf is incorrect: printf(nums) should not even compile, or at least generate meaningful warnings.

Note that you do not need to use strtok() at all. strtol() can parse a number and update a pointer to point past the number.

Here is how to use that:

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

int main(int argc, char *argv[]) {
    printf("Starting program\n");
    if (argc < 2) {
        fprintf(stderr, "missing command line argument\n");
        return 1;
    }
    FILE *fp = fopen(argv[1], "r");
    if (fp == NULL) {
        fprintf(stderr, "cannot open %s: %s\n", argv[1], strerror(errno));
        return 1;
    }
    char buf[1000];
    int nums[1000];
    int i = 0; 

    while (fgets(buf, sizeof buf, fp)) {
        char *p = buf;
        char *q;
        for (; i < 1000; i++) {
            nums[i] = strtol(p, &q, 0);
            if (q == p) {
                /* no more numbers */
                break;
            }
            p = q;
        }
    }
    fclose(fp);
    for (int j = 0; j < i; j++) {
        printf("%d ", nums[j]);
    }
    printf("\n");
    return 0;
}

You are not checking argc and derefencing args[1] and args[2] .

You never use number .

Try this:

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

int main( int argc, char * argv[] ) {
   printf("Starting program\n");
   if( argc < 2 ) {
      return 1;
   }
   FILE * fp = fopen( argv[1], "r");
   if( fp == NULL ) {
      perror( argv[1] );
      return 1;
   }
   char int_array[1000];
   if( fgets( int_array, 1000, fp )) {
      int nums[1000];
      int    i = 0; 
      char * token = strtok(int_array, " ");
      while( token ) {
         nums[i++] = atoi(token);
         token = strtok(NULL, " ");
      }
      printf("0: %i\n", nums[0]);
      printf("1: %i\n", nums[1]);
      printf("%d: %i\n", i-1, nums[i-1]);
   }
   return 0;
}

Execution:

aubin@Breizh-Atao ~/Dev/C $ gcc parsing.c -o parsing
aubin@Breizh-Atao ~/Dev/C $ echo 1 2 3 4 5 6 7 8 9 10 11 >parsing.txt
aubin@Breizh-Atao ~/Dev/C $ ./parsing parsing.txt 
Starting program
0: 1
1: 2
10: 11
aubin@Breizh-Atao ~/Dev/C $ 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM