Spilt a string of integers based on delimiter and convert to int type?

杀马特。学长 韩版系。学妹 提交于 2019-12-13 22:22:31

问题


I am writing a program that takes a file of ordered pairs of numbers as it's input, and I want to split those ordered pairs and convert them to an integer for storage in an array.

The file could be like this:

0 1
1 4
9 11
12 45

I want to write a function that takes in the line, (assumed to be already null terminated in another part of the program), splits the numbers at the space and then stores them in a integer array of size two:

 int *store = malloc(2 * sizeof(store));

I have looked into strtok but am I correct to say that it's not thread-safe and hence not the best option in this situation? Also it won't convert the numbers to integers which is something the function also needs to have.

How can I solve this problem?


回答1:


If you want to read an unknown number of ordered pairs into an array of ordered pairs, there are a number of ways to approach this. As noted in the comment, if you can guarantee that you will always have 2-integers per line, the probably the simplest way to approach reading/converting the values to integers is with fscanf

(when you have the exact same format of data on each line is one of the only times I would recommended fscanf over fgets and sscanf, and then it is only to simplify the example)

When you have an unknown number of elements to read, the basic scheme is to allocate memory for some reasonably anticipated number pairs and then realloc as needed. Since you are reading ordered-pairs, you can simplify the process by allocating storage for an pointer-to-array-of-two-int. For example with your array of ordered-pairs op declared as follows:

    int (*op)[2] = NULL;

you can allocate storage for MXLINE number of pairs with:

    op = calloc (MXLINE, sizeof *op);

(you can use either malloc or calloc to allocate)

After you allocate initial memory to hold your ordered pairs, you can simply read each line with a format string containing two decimal conversion specifiers (e.g. "%d %d") and have fscanf perform the conversion. You must validate 2 conversions take place and then store the values in your array.

Keep a running count of the number of pairs you add so you can realloc when you reach your limit. An example is shown below. Don't forget to free all memory when it is no longer needed, and also run your code through a memory checker to validate your use of dynamically allocated memory.

Putting it all together in a short example using your datafile, you could do something like the following. Note: the program will read from the file given as the first argument on the command line (or from stdin by default if no filename is given):

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

#define MXLINE 2

int main (int argc, char **argv) {

    int i, idx = 0, mxline = MXLINE;
    int (*op)[2] = NULL;
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    /* allocate/validate initial memory */
    if (!(op = calloc (MXLINE, sizeof *op))) {
        fprintf (stderr, "error: virtual memory exhausted.\n");
        return 1;
    }

    /* read each ordered pair into 'op' array */
    while (fscanf (fp, "%d %d", &op[idx][0], &op[idx][1]) == 2) {
        if (++idx == mxline) { /* realloc when limit reached */
            void *tmp = realloc (op, sizeof *op * mxline * 2);
            if (!tmp) { /* validate reallocation */
                fprintf (stderr, "error: realloc failed.\n");
                break;
            }
            op = tmp;    /* assign reallocated pointer to op */
            mxline *= 2; /* update line allocation limit */
        }
    }

    for (i = 0; i < idx; i++) /* show ordered pairs */
        printf ("pair[%3d] %3d : %3d\n", i, op[i][0], op[i][1]);

    free (op);  /* free allocated memory */

    if (fp != stdin)    /* close file if not stdin */
        fclose (fp);

    return 0;
}

Example Use/Output

$ ./bin/array_ptr2array <dat/orderedpairs.txt
pair[  0]   0 :   1
pair[  1]   1 :   4
pair[  2]   9 :  11
pair[  3]  12 :  45

Memory/Error Check

Do not forget to validate your use of dynamically allocated memory and that your are freeing all memory when it is no longer needed:

$ valgrind ./bin/array_ptr2array <dat/orderedpairs.txt
==8107== Memcheck, a memory error detector
==8107== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==8107== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==8107== Command: ./bin/array_ptr2array
==8107==
pair[  0]   0 :   1
pair[  1]   1 :   4
pair[  2]   9 :  11
pair[  3]  12 :  45
==8107==
==8107== HEAP SUMMARY:
==8107==     in use at exit: 0 bytes in 0 blocks
==8107==   total heap usage: 3 allocs, 3 frees, 112 bytes allocated
==8107==
==8107== All heap blocks were freed -- no leaks are possible
==8107==
==8107== For counts of detected and suppressed errors, rerun with: -v
==8107== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)

(note: the initial allocation was for MXLINE (2) pairs. The was intentionally done to force reallocation. In the real world you will want to minimize the number of times your must allocate memory. So if you think you could have 20 or so pairs, set the initial allocation for 24 or 32 pairs or whatever is your best reasonable guess of the number you will have (plus a couple for good-measure))

Look it over and let me know if you have any questions.




回答2:


Maybe this is a solution:

gets(str, 80, fp); // get a line
sscanf(str, "%d %d", &store[0], &store[1]); // read numbers from that line


来源:https://stackoverflow.com/questions/36299842/spilt-a-string-of-integers-based-on-delimiter-and-convert-to-int-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!