-5

I have made a matrix in MatLab and exported it as a CSV. I don't really know how to use it in my C code though. For example, my table looks like this (allthough much bigger and more complicated values):

Height/Angle, 50, 550, 1050, 1550, 2050
5, 0.9, 0.8, 0.7, 0.6, 0.5
6, 0.8, 0.7, 0.6, 0.5, 0.4
7, 0.7, 0.6, 0.5, 0.4, 0.3
8, 0.6, 0.5, 0.4, 0.3, 0.2
9, 0.5, 0.4, 0.3, 0.2, 0.1

So what I want is a function that takes two arguments and returns the corresponding value from the table. I have a program that gives me the height and the angle of a plane, seen from an IR-sensor, and given those values I want the corresponding value. For example: GetValueFromCSV(550,7); should return 0.6 in my example. But I have no idea how to do this. I have done some research with ´strtok()`, but that doesn't really seem like what I need. Please help out a noob.

  • Why C? Use Perl or Python for such purpose. You can find plenty of examples, just google it (Example: https://pythonspot.com/reading-csv-files-in-python/). – Alex Lop. Oct 04 '18 at 10:29
  • 1
    `strtok` is exactly what you need. Have a read on file input: https://www.cs.bu.edu/teaching/c/file-io/intro/ basically, you want to read your csv line by line until you reach the right line, then use `strtok` to get the correct position in that line. Happy coding! – Blaze Oct 04 '18 at 10:31
  • The thing is, I'm locked to using C since it is underlying for another environment called FLAMES that I'm working in :/ – Anders Hamfeldt Oct 04 '18 at 10:31
  • 1
    I like InFLAMES. Especially "Reroute to Remain" – Swordfish Oct 04 '18 at 10:33
  • Sry Swordfish, that was a typo. It should return 0,6. – Anders Hamfeldt Oct 04 '18 at 10:42
  • You can find a basic CSV parser in http://stackoverflow.com/questions/32349263/c-regex-how-to-match-any-string-ending-with-or-any-empty-string/32351114#32351114. Use it to build your finction on top of this. – Paul Ogilvie Oct 04 '18 at 12:07

1 Answers1

0

. o O ( yes, code-only answer cause code is quite self-explanatory )

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

typedef struct row_tag
{
    int index;
    double *data;
} row_t;

size_t get_col_count(FILE *is)
{
    size_t col_count = 1;

    int ch;
    while ((ch = fgetc(is)) != EOF && ch != '\n')
        if (ch == ',')
            ++col_count;

    rewind(is);
    return col_count;
}

row_t* csv_read(FILE *is, size_t *cols, size_t *rows)
{
    *cols = get_col_count(is);
    *rows = 0;
    char const *origin_format = "%*[^ ,]%c";
    char const *row_header_format = "%d%c";
    char const *format = "%lf%c";
    row_t *csv = NULL;

    bool valid = true;
    for (size_t current_row = 0; valid; ++current_row) {
        csv = realloc(csv, (current_row + 1)* sizeof(row_t));
        csv[current_row].data = calloc(cols - 1, sizeof(double));

        for (size_t current_col = 0; valid && current_col < cols; ++current_col) {

            char delim;
            if (!current_col && !current_row) {
                if (fscanf(is, origin_format, &delim) != 1 || delim != ',') {
                    valid = false;
                    continue;
                }
                csv[0].index = -1;
            }
            else if (!current_col) {
                int result = -1;
                if ((result = fscanf(is, row_header_format, &csv[current_row].index, &delim)) != 2 || delim != ',') {
                    valid = false;
                    continue;
                }
            }
            else {
                if (fscanf(is, format, &csv[current_row].data[current_col - 1], &delim) != 2 || delim != ',' && delim != '\n')
                    valid = false;
            }
        }

        if (!valid)
            free(csv[current_row].data);
        else *rows = current_row + 1;
    }

    return csv;
}

void csv_free(row_t *csv, size_t rows)
{
    for (size_t row = 0; row < rows; ++row)
        free(csv[row].data);
    free(csv);
}

double csv_get_value(row_t *csv, int col_index, size_t cols, int row_index, size_t rows)
{
    size_t col;
    for (col = 1; csv[0].data[col] != col_index && col < cols; ++col);
    if (col >= cols || csv[0].data[col] != col_index)
        return 0.;

    size_t row;
    for (row = 1; csv[row].index != row_index && row < rows; ++row);
    if (row >= rows || csv[row].index != row_index)
        return 0.;

    return csv[row].data[col];
}

int main(void)
{
    char const *filename = "test.txt";
    FILE *is = fopen(filename, "r");
    if (!is) {
        fprintf(stderr, "Couldn't open \"%s\" for reading!\n\n", filename);
        return EXIT_FAILURE;
    }

    size_t cols;
    size_t rows;
    row_t *csv = csv_read(is, &cols, &rows);
    printf("Cols: %zu\nRows: %zu\n\n", cols, rows);

    fclose(is);

    // have fun with csv:
    for (size_t y = 0; y < rows; ++y) {
        printf("%2d: ", csv[y].index);
        for (size_t x = 0; x < cols - 1; ++x)
            printf("%f ", csv[y].data[x]);
        putchar('\n');
    }

    double value = csv_get_value(csv, 550, cols, 7, rows);
    printf("\n%f\n", value);


    csv_free(csv, rows);
}

Output:

Cols: 6
Rows: 6

-1: 50.000000 550.000000 1050.000000 1550.000000 2050.000000
 5: 0.900000 0.800000 0.700000 0.600000 0.500000
 6: 0.800000 0.700000 0.600000 0.500000 0.400000
 7: 0.700000 0.600000 0.500000 0.400000 0.300000
 8: 0.600000 0.500000 0.400000 0.300000 0.200000
 9: 0.500000 0.400000 0.300000 0.200000 0.100000

0.600000
Swordfish
  • 12,971
  • 3
  • 21
  • 43