Я привык к Java, но изучаю C ++, и в качестве эксперимента я пытаюсь создать библиотеку, которая будет считывать файл CSV в 2-мерный массив с определенными пользователем спецификациями импорта, печатать массив на консоли, а затем записывать массив в отдельный файл.

Я застрял в том, как определить количество строк (ось Y), которые нужно пройти в 2-м массиве при создании массива, печати массива и записи массива. У меня есть значение оси x, и я возился с этим:

int y = sizeof(arr) / sizeof(arr[0]);

Чтобы попытаться получить это. Когда я тестировал код в одной скомпилированной cpp main, у него было правильное количество строк, но теперь, когда я переместил функции во включенную библиотеку, он присваивает 0 переменной y!

В чем разница и как ее устранить? В приведенном ниже примере я тестирую матрицу с 6 полями и 4 записями, поэтому я ожидаю 4 в качестве значения, присвоенного y.

Поскольку я сузил проблему до этой переменной, вот (надеюсь) SSCCE того, как я получаю y.

Заголовочный файл:

#ifndef CSV_IO_H
#define CSV_IO_H

#include <string>

using namespace std;

class csv_io
{
    public:
        static void csv_to_dbl_arr(string, double arr[][6], char, char);
        static void print_dbl_arr(double arr[][6]);
};

#endif

Включенная библиотека:

#include "csv_io.h"
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>

using namespace std;

void csv_io::csv_to_dbl_arr(string inf, double arr[][6], char dlm, char sep)
{
    ifstream ifs;
    string row, col, val;
    int i = 0;
    int j = 0;

    ifs.open(inf.c_str());
    if(ifs.is_open())
    {
        while(ifs.good())
        {
            getline(ifs, row, sep);
            stringstream col(row);

            while(col.good())
            {
                getline(col, val, dlm);
                arr[i][j] = atof(val.c_str());
                j++;
            }
            j = 0;
            i++;
        }
    }
    ifs.close();
}

void csv_io::print_dbl_arr(double arr[][6])
{
    int x = sizeof(arr[0]) / sizeof(double);
    int y = sizeof(arr) / sizeof(arr[0]);

    cout << "x: " << x << endl << "y: " << y << endl;
}

main.cpp :

#include "csv_io.h"
#include "csv_io.cpp"
#include <stdlib.h>

using namespace std;

int main()
{
    double d_arr[4][6];

    string inf = "file_i.txt";

    char in_dlm = ',';
    char in_sep = '\n';

    csv_io::csv_to_dbl_arr(inf, d_arr, in_dlm, in_sep);
    csv_io::print_dbl_arr(d_arr);

    return 0;
}

file_i.txt:

1,1,1,1,1,1
2,2,2,2,2,2
3,3,3,3,3,3
4,4,4,4,4,4

Я знаю, что могу сделать счетчик и отслеживать количество строк в csv_to_dbl_arr, но я хочу выяснить выражение, которое я использую для y, чтобы я мог использовать его на лету, не объявляя его в main.

1
Matt Dexter 25 Июл 2014 в 11:12

3 ответа

Лучший ответ

void print_dbl_arr(double arr[][6]) эквивалентно
void print_dbl_arr(double (*arr)[6])

Так

  • sizeof(arr) - размер указателя
  • sizeof(arr[0]) - это размер double (&)[6], поэтому 6 * sizeof double.

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

template <std::size_t N, std::size_t M>
void print_dbl_arr(double (&arr)[N][M]);

Использование std::vector / std::array более интуитивно понятно.

1
Jarod42 25 Июл 2014 в 07:56

Когда вы передаете в функцию массив integer / float / double, это означает, что вы передаете только базовый адрес массива (поскольку имя массива представляет базовый адрес)

В следующей функции:

void csv_io::print_dbl_arr(double arr[][6])
{
   int x = sizeof(arr[0]) / sizeof(double); // here you are dividing sizeof(address of array) with sizeof(double)
   // because arr and arr[0] both represents the base address of the array in 2D array
   int y = sizeof(arr) / sizeof(arr[0]); // Its indirectly means that dividing the size of base addresses
   cout << "x: " << x << endl << "y: " << y << endl;
}

Чтобы избежать этой ошибки типа всякий раз, когда вы передаете одномерный массив функции, вы должны передать общее количество элементов в этом массиве. Для 2D-массива вам необходимо передать значение строки и столбца в функцию с базовым адресом массива.

Надеюсь, что это поможет вам!

1
marc_s 21 Апр 2016 в 21:00
double d_arr[4][6];

void csv_io::print_dbl_arr(double arr[][6])
    {
        int x = sizeof(arr[0]) / sizeof(double);
        int y = sizeof(arr) / sizeof(arr[0]);

        cout << "x: " << x << endl << "y: " << y << endl;
    }

csv_io::print_dbl_arr(d_arr);

Когда вы передаете массив d_arr в print_dbl_arr, он превращается в указатель (double (*arr)[6]). Итак, sizeof(arr) равно 4 на 32-битных платформах. А arr[0] - это одномерный массив из шести чисел двойной точности, имеющий размер 48 (предполагается, что sizeof(double) равно 8). Результат целочисленного деления 4/48 равен нулю.

То же самое происходит с одномерным массивом (в обоих случаях [] указан для самого высокого измерения). Вот почему нам нужно передать количество элементов массива в качестве другого параметра, чтобы вызываемый мог это знать.

int arr[4];
void f(int arr[], int n)
{
    // The wrong way
    // arr is decayed to a pointer, int *arr.
    // for (size_t i = 0; i < sizeof(arr); ++i)
    // {
    //    // iterate over the array
    // }

    // The correct way
    for (size_t i = 0; i < n; ++i)
    {
        // iterate over the array
    }
}
1
Eric Z 25 Июл 2014 в 07:40