Экспорт данных в CSV в C


Я просто выучил основы C и я построил рабочую программу, которая считывает набор данных, предоставленных моими преподаватель и экспорт его в CSV.

Однако, он сказал, что это может быть упрощенной (много!) чтобы просто распечатать значения данные в нужные столбцы (х, у, Z). Но я не вижу, как это может сработать, учитывая мои настройки.

Это мой первый кодирования времени (я студент медицинского) и я немного ошеломлен. Как я уже сказал, мне просто нравится мой код, чтобы быть пересмотрены и способы, чтобы сделать его проще и просто распечатать значения.

Пустота create_CSV и тап_п создаются себя, в то время как gen_sally создается мой преподаватель.

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

void gen_sally( int xs, int ys, int zs, int time, float *sally )
/*
 *  Gen_Sally creates a vector field of dimension [xs,ys,zs,3] from
 *  a proceedural function. By passing in different time arguements,
 *  a slightly different and rotating field is created.
 *
 *  The magnitude of the vector field is highest at some funnel shape
 *  and values range from 0.0 to around 0.4 (I think).
 *
 *  I just wrote these comments, 8 years after I wrote the function.
 *  
 *  Developed by Sally of Sally University
 *
 */
{
  float x, y, z;
  int ix, iy, iz;
  float r, xc, yc, scale, temp, z0;
  float r2 = 8;
  float SMALL = 0.00000000001;
  float xdelta = 1.0 / (xs-1.0);
  float ydelta = 1.0 / (ys-1.0);
  float zdelta = 1.0 / (zs-1.0);

  for( iz = 0; iz < zs; iz++ )
  {
     z = iz * zdelta;                        // map z to 0->1
     xc = 0.5 + 0.1*sin(0.04*time+10.0*z);   // For each z-slice, determine the spiral circle.
     yc = 0.5 + 0.1*cos(0.03*time+3.0*z);    //    (xc,yc) determine the center of the circle.
     r = 0.1 + 0.4 * z*z + 0.1 * z * sin(8.0*z); //  The radius also changes at each z-slice.
     r2 = 0.2 + 0.1*z;                           //    r is the center radius, r2 is for damping
     for( iy = 0; iy < ys; iy++ )
     {
        y = iy * ydelta;
        for( ix = 0; ix < xs; ix++ )
        {
            x = ix * xdelta;
            temp = sqrt( (y-yc)*(y-yc) + (x-xc)*(x-xc) );
            scale = fabs( r - temp );
/*
 *  I do not like this next line. It produces a discontinuity 
 *  in the magnitude. Fix it later.
 *
 */
           if ( scale > r2 )
              scale = 0.8 - scale;
           else
              scale = 1.0;
            z0 = 0.1 * (0.1 - temp*z );
           if ( z0 < 0.0 )  z0 = 0.0;
           temp = sqrt( temp*temp + z0*z0 );
            scale = (r + r2 - temp) * scale / (temp + SMALL);
            scale = scale / (1+z);
           *sally++ = scale * (y-yc) + 0.1*(x-xc);
           *sally++ = scale * -(x-xc) + 0.1*(y-yc);
           *sally++ = scale * z0;
        }
     }
  }
}


void create_csv(char* filename,float *sally, int size){

    printf("1");

    printf("\n Creating %s.csv file",filename);

    FILE *fp;

    fp=fopen(filename,"w");

    fprintf(fp,"X,Y,Z\n");
    int i;
    int counter = 0;

    for(i = 0; i< size; i++){
        if(sally[i] == 0){
            fprintf(fp,"0");
        } else {
            fprintf(fp,"%f",sally[i]);
        }
            counter++;
            if(counter == 3){
                fprintf(fp, "\n");
                counter = 0;
        } else {
            fprintf(fp,",");
        }
    }

    fclose(fp);
    printf("\n %sfile created",filename);
}


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

    printf("1\n");
    //read from args
    int xs;
    int ys;
    int zs;
    int time;
    sscanf(argv[1],"%d",&xs);
    sscanf(argv[2],"%d",&ys);
    sscanf(argv[3],"%d",&zs);
    sscanf(argv[4],"%d",&time); // Is a constant, will always be reads as 1


    int arraySize = xs*ys*zs*1;

    //allocate memeory for array. This is done so that stack memory doesn't run out.'
    float* sally;
    sally = (float*)malloc((arraySize) * sizeof(float));

    //runs the code. One of the args is a pointer so no return type is needed. 
    gen_sally(xs,ys,zs,time,sally);

    //create varibles for file generation
    char filename[20] = "results.csv";
    create_csv(filename, sally, arraySize);

    free(sally);
    return 0;
}


205
4
задан 8 апреля 2018 в 07:04 Источник Поделиться
Комментарии
4 ответа

В main() есть линии

    int arraySize = xs*ys*zs*1;

Ничего, 1 раз сама, поэтому нет никаких причин, чтобы умножить на 1.

В create_csv() функция, переменная counter не нужен - переменная i можно использовать вместо с помощью модуля оператора:

    if (i % 3) {
fprintf(fp, ",");
}
else {
fprintf(fp, "\n");
}

Альтернативное Упрощение это может быть:

    fprintf(fp, "%c",  (i % 3)? ',' : '\n');

Также в create_csv()вы могли бы обойтись с одним printf() заявление, а не два:

    printf("1\n Creating %s.csv file\n", filename);

В main()лучше программирования для malloc() можно было бы использовать

sizeof *sally

а не

sizeof(float)

потому что типа sally может измениться в какой-то момент; с помощью *sally только одну строку кода нужно менять, а не несколько строк кода. В cast в результате malloc() не надо.

    float* sally;
sally = malloc((sizeof *sally) * arraySize);

Этот код вызывает сомнение:

    if (sally[i] == 0) {
fprintf(fp, "0");
}
else {
fprintf(fp, "%f", sally[i]);
}

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

Это было требование записать нулевое значение в качестве 0? Если нет, то код можно упростить до

void create_csv(char* filename, float *sally, int size) {
printf("1\n Creating %s.csv file\n", filename);

FILE *fp;

fp = fopen(filename, "w");

fprintf(fp, "X,Y,Z\n");
int i;

for (i = 0; i < size; i++) {
fprintf(fp, "%f%c", sally[i], (i % 3) ? ',' : '\n');
}

fclose(fp);
printf("\n %sfile created", filename);
}

2
ответ дан 8 апреля 2018 в 03:04 Источник Поделиться

Всегда проверяйте, являются ли операции ввода-вывода были успешными

Такой код является проблематичным:

FILE *fp = fopen(filename, "w");
fprintf(fp,"X,Y,Z\n");

Если нам не удалось открыть файл, мы получим нулевой указатель, присваивается fp. Если нам повезет, то программа будет выжить передает, что fprintf()и мы будем иметь никаких признаков того, что данные не были сохранены. Что может быть серьезной проблемой, если это означает, что пользователь считает, что их данные были надежно сохранены.

Аналогичным образом, мы должны проверить возвращаемое значение sscanf() при использовании на аргументы, прежде чем мы попытаемся использовать те ценности, которые мы читаем. (Альтернативный вариант - рассмотрим strtoul() или strtoul(), чтобы мы могли проверить, что нет ненужных следующее действительное число).

1
ответ дан 9 апреля 2018 в 03:04 Источник Поделиться

поплавок V двойной

Переменные float еще константы (0.4, 0.1,...) и функций (sin(), cos()) являются двойными. Это было бы более последовательно использовать float или double на протяжении.

 float xc, time, z;
xc = 0.5f + 0.1f*sinf(0.04f*time + 10.0f*z);
// or
double xc, time, z;
xc = 0.5 + 0.1*sin(0.04*time + 10.0*z);

точность скорости V

hypot() обычно более точный, хотя иногда медленнее, чем размещен код.

temp = sqrt( (y-yc)*(y-yc) + (x-xc)*(x-xc) );
// Alternative:
temp = hypot(y-yc, x-xc);
temp = hypotf(y-yc, x-xc); // using float only.

%ф В %Г

Напомним, что числа с плавающей точкой имеют плавающую точку. С "%f"большое число будет напечатано с много ненужных персонажей и малых чисел напечатает 0.000000. Он является более информативным (особенно во время отладки), чтобы печатать цифры, чем в формате с фиксированной запятой. Предлагаю использовать "%g" или "%e".

// fprintf(fp,"%f",sally[i]);
fprintf(fp,"%g",sally[i]);

0
ответ дан 10 апреля 2018 в 11:04 Источник Поделиться

Противоречивые/отсутствие интервала

Пожалуйста, не делайте этого, как это: 0.1 + 0.4 * z*z + 0.1 * z * sin(8.0*z);окружают все математические операторы с пробелами везде. Не просто в случайных местах.

Комментарии

Пожалуйста, не добавляйте стену комментарии между определением функции и ее тела. Это действительно трудно читать. Как правило, функция прокомментировал перед определением функции, поэтому... следующим будет предпочтительным:

/*
* Gen_Sally creates a vector field of dimension [xs,ys,zs,3] from
* a proceedural function. By passing in different time arguements,
* a slightly different and rotating field is created.
* @param[in]
* ...
* @param[out]
*/
void gen_sally(int xs, int ys, int zs, int time, float *sally)

Следующие замечания также довольно сумбурно для чтения:

 z = iz * zdelta;                        // map z to 0->1
xc = 0.5 + 0.1*sin(0.04*time+10.0*z); // For each z-slice, determine the spiral circle.
yc = 0.5 + 0.1*cos(0.03*time+3.0*z); // (xc,yc) determine the center of the circle.
r = 0.1 + 0.4 * z*z + 0.1 * z * sin(8.0*z); // The radius also changes at each z-slice.
r2 = 0.2 + 0.1*z; // r is the center radius, r2 is for damping

Разрывы строк и т. д. Почему не просто выбор лучшего названия для переменных? И описывая все, что произойдет до фактического кода?

Проверить на вменяемость

Ваш не проверки на нулевой указатель, недопустимых значений и т. д. Ни одна из ваших функций может давать сбой и возвращать ошибку, и т. д

0
ответ дан 10 апреля 2018 в 12:04 Источник Поделиться