strtok () для печати файла CSV (ноль) вместе с желаемым значением - PullRequest
0 голосов
/ 07 марта 2019

Я пытаюсь прочитать CSV-файл в C и сохранить эти данные в vector .

Мои записи CSV-файла для каждой строки выглядят так: 12/12/1914, 52.4, однако,Меня интересует только получение номера из этого CSV, а не даты.Чтобы добиться этого, я пытался прочитать файл построчно с помощью fgets(), а затем отделить числовое значение с помощью strtok().

Когда я распечатываю результаты strtok(), я получаю числа, которые ищу, но я также печатаю (null) с ними:

(null)
25798.42

(null)
25706.68

(null)
25379.45

(null)
25444.34

(null)
25317.41

Кроме того, когда я пытаюсьи печатать фактический вектор, они просто выводят мусор (я полагаю, это потому, что к ним прикреплен (null), но не положительный):

3907216808; 0; 
3907216808; 0; 

Моя функция для чтения данных выглядит следующим образом:

void get_CSV_data(vc_vector* prices)
{
    FILE *fp = fopen(_FILE_PATH, "r");
    char singleLine[20];

    while(!feof(fp)){
        fgets(singleLine, 20, fp);

        char* token = strtok(singleLine, ",");
        while (token != NULL) {
            token = strtok(NULL, ",");
            printf("%s\n", token);
            vc_vector_push_back(prices, &token);
        }
    }
    // Print each vector element
    for (void* i = vc_vector_begin(prices);
         i != vc_vector_end(prices);
         i = vc_vector_next(prices, i)) {
         printf("%u; ", *(int*)i);
    }
}

Я предполагаю, что я неправильно использую strtok(), кто-нибудь может посоветовать?Кроме того, пока я здесь, быстрый побочный вопрос, нужен ли free(token); в какой-то момент?Или нет, потому что malloc() никогда не вызывали?Все еще довольно плохо знаком с C.

РЕДАКТИРОВАТЬ: моя функция теперь выглядит следующим образом:

    void get_CSV_data(vc_vector* prices)
{
    FILE *fp = fopen(_FILE_PATH, "r");
    char singleLine[20];

    while(fgets(singleLine, 20, fp) != NULL){
        char* token = strtok(singleLine, ",");
        token = strtok(NULL, ",");
        //printf("%s\n", token);
        vc_vector_push_back(prices, strdup(token));


    }
    // Print each vector element
    for (void* i = vc_vector_begin(prices);
         i != vc_vector_end(prices);
         i = vc_vector_next(prices, i)) {
         printf("%s\n ", (char*)i);
    }
}

Я получаю результаты как:

25598.7425052.8325339.9925250.5525798.4225706.6825379.4525444.3425317.4125191.43    25052.8325339.9925250.5525798.4225706.6825379.4525444.3425317.4125191.43
25339.9925250.5525798.4225706.6825379.4525444.3425317.4125191.43
25250.5525798.4225706.6825379.4525444.3425317.4125191.43
25798.4225706.6825379.4525444.3425317.4125191.43
25706.6825379.4525444.3425317.4125191.43
25379.4525444.3425317.4125191.43

Какие правильные.

Ответы [ 3 ]

2 голосов
/ 07 марта 2019

В

   char* token = strtok(singleLine, ",");
   while (token != NULL) {
       token = strtok(NULL, ",");
       printf("%s\n", token);
       vc_vector_push_back(prices, &token);
   }

vc_vector_push_back позволяет сохранять данные, имеющие заданный размер, а не переменный размер, поэтому вы можете использовать его, только если вы создали вектор, указывающий количество символов, которое вы вставите в

В вашем случае вы делаете vc_vector_push_back(prices, &token);, так что вы наконец сохраните хотя бы адрес строки, запомненной в token , это неправильно, вам нужно сохранить символы внутри строки:

    char* token = strtok(singleLine, ",");
    while (token != NULL) {
        token = strtok(NULL, ",");
        printf("%s\n", token);
        vc_vector_push_back(prices, token);
    }

дублировать токен бесполезно (как я сначала себе представлял), потому что vc_vector_push_back сделает копию в зависимости от размера, который вы указали при создании вектора

Обратите внимание, что вы также теряете первый токен и, наконец, нажмете NULL, возможно, вы захотите

    char* token = strtok(singleLine, ",");
    while (token != NULL) {
        printf("%s\n", token);
        vc_vector_push_back(prices, token);
        token = strtok(NULL, ",");
    }

В

 for (void* i = vc_vector_begin(prices);
      i != vc_vector_end(prices);
      i = vc_vector_next(prices, i)) {
      printf("%u; ", *(int*)i);
 }

вы полагаете, цены содержит int , но это неверно, оно содержит char*, должно быть

  for (void* i = vc_vector_begin(prices);
       i != vc_vector_end(prices);
       i = vc_vector_next(prices, i)) {
       printf("%s ", *(char**)i);
  }

Вам также нужно изменить

while(!feof(fp)){
    fgets(singleLine, 20, fp);

чем-то вроде

while (fgets(singleLine, 20, fp) != NULL) {

Я также рекомендую вам проверить значение fopen(...), прежде чем использовать его

0 голосов
/ 07 марта 2019

Когда я распечатываю результаты strtok (), я получаю числа, которые ищу, но я также печатаю (ноль) с ними:

Да, потому что вы зацикливаетесьпока не сделаешь.Рассмотрим:

        while (token != NULL) {
            token = strtok(NULL, ",");
            printf("%s\n", token);
            vc_vector_push_back(prices, &token);
        }

Пока исходный токен не равен NULL, на каждой итерации вы читаете и затем печатаете следующий токен.Только тогда, после того, как вы уже напечатали его, вы возвращаетесь к циклу, чтобы проверить, является ли он нулевым.

Поскольку вам, кажется, требуется ровно второй токен каждой строки, бессмысленно выполнять цикл.Просто позвоните strtok() дважды:

        char* token = strtok(singleLine, ",\n");

        if (token) {
            token = strtok(NULL, ",\n");
            if (token) {
                printf("%s\n", token);
                vc_vector_push_back(prices, &token);  // but see below
            } // else handle malformed data
        } // else handle malformed data

Кроме того, пока я здесь, быстрый вопрос, это free(token);нужно в какой-то момент?Или нет, потому что malloc() никогда не вызывался?

Нет, потому что, как вы говорите, память не была выделена.Но подумайте о последствиях.Память не выделяется, потому что token указывает на локальный массив singleLine, который вы токенизируете.Это означает:

  1. Когда вы читаете следующую строку в том же буфере, вы заменяете наведенные данные.
  2. Когда функция возвращается, время жизни этого массива заканчивается, рендеринглюбые указатели (in) на него недействительны.

Похоже, что vc_vector копирует элементы в, но в вашем случае это может быть только копирование самих указателей, а не значений, на которые они указывают, так чтоне помогает вообще ни с одним из вышеперечисленного.Вместо этого, чтобы не повредить ваши данные и в конечном итоге иметь вектор, полный висячих указателей, вы должны делать динамически распределяемые копии строк токенов и сохранять указатели на этих в вашем векторе.

Если он у вас есть, то нестандартная, но распространенная функция strdup() может сделать такие копии для вас.В противном случае комбинация strlen(), malloc() и strcpy() будет выполнять ту же работу.Обратите внимание, что даже при отсутствии явного вызова функции распределения при использовании strdup() в случае успеха получающаяся в результате дублирующаяся строка действительно выделяется динамически, и ее нужно освобождать, когда она больше не нужна.

Кроме того, когда я пытаюсь распечатать фактический вектор, они просто выводят мусор

Ну это , потому что вы храните указатели на массивы символов в вашем векторе, нозатем пытается интерпретировать их, как если бы они были указателями на int.Форматы указателей, вероятно, совместимы, но данные, на которые они указывают, совершенно не совместимы.А тип int даже не является подходящим типом, поскольку ваши данные не являются целочисленными (если только вы не можете преобразовать их в представление с фиксированной запятой).Возможно, вместо дублирования строк вы хотите использовать и разрешить копировать вектор, double s:

double d = strtod(token, NULL);  // note: as written, performs no error checking
vc_vector_push_back(prices, &d);

Это может потребовать изменения способа инициализации вектора.Затем вы напечатаете их как двойные числа, скажем:

for (double *dp = vc_vector_begin(prices);
        dp != vc_vector_end(prices);
        dp = vc_vector_next(prices, dp)) {
     printf("%.2f; ", *dp);
}
0 голосов
/ 07 марта 2019

После проверки token != NULL в условии while вы выполняете еще одну token = strtok(NULL, ",");. Это дает - один из последних достигнутых токенов - 100% «шанс» получить значение NULL, которое вы впоследствии распечатываете:

while (token != NULL) {
        token = strtok(NULL, ",");
        printf("%s\n", token);

Поместите strtok в последнюю строку в цикле:

while (token != NULL) {
        printf("%s\n", token);
        vc_vector_push_back(prices, &token);
        token = strtok(NULL, ",");

Фурхтер, вы храните указатели на локальную переменную, к которой - при выходе из области видимости - больше нельзя получить доступ. Вам нужно будет скопировать значения:

while (token != NULL) {
        printf("%s\n", token);
        token = strdup(token);
        vc_vector_push_back(prices, &token);
        token = strtok(NULL, ",");
...