Search code examples
cfwritenidaqmx

fwrite() dynamic array to a file


I'm trying to save a dynamic array to a file but I'm having some issues. This is my current code:

/*********************************************************************
*
* ANSI C Example program:
*    Acq-IntClk.c
*
* Example Category:
*    AI
*
* Description:
*    This example demonstrates how to acquire a finite amount of data
*    using the DAQ device's internal clock.
*
* Instructions for Running:
*    1. Select the physical channel to correspond to where your
*       signal is input on the DAQ device.
*    2. Enter the minimum and maximum voltages.
*    Note: For better accuracy try to match the input range to the
*          expected voltage level of the measured signal.
*    3. Select the number of samples to acquire.
*    4. Set the rate of the acquisition.
*    Note: The rate should be AT LEAST twice as fast as the maximum
*          frequency component of the signal being acquired.
*
* Steps:
*    1. Create a task.
*    2. Create an analog input voltage channel.
*    3. Set the rate for the sample clock. Additionally, define the
*       sample mode to be finite and set the number of samples to be
*       acquired per channel.
*    4. Call the Start function to start the acquisition.
*    5. Read all of the waveform data.
*    6. Call the Clear Task function to clear the task.
*    7. Display an error if any.
*
* I/O Connections Overview:
*    Make sure your signal input terminal matches the Physical
*    Channel I/O Control. For further connection information, refer
*    to your hardware reference manual.
*
*********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <NIDAQmx.h>
#include <string.h>
#include <windows.h>


#define DAQmxErrChk(functionCall) if( DAQmxFailed(error=(functionCall)) ) goto Error; else
FILE *save_file = NULL;

int main(void)
{
    int32       error=0;
    int32       amount; 
    int32       counter[2]={'0'};
    TaskHandle  taskHandle=0;
    int32       read;
    float64*    i_array;
    int         j;
    char        errBuff[2048]={'\0'};
    char        c = 64;
    char        filename[256];

    char        answer[2];
    const int       ia=0;
    const char      a = 0;

    i_array = (float64*)malloc(j*sizeof(int));

    /*********************************************/
    // DAQmx Configure Code
    /*********************************************/

    printf("Please enter the amount of voltage checks you wish to run.\n");

    while(scanf("%d%c", &amount, &c) !=2) // This is where the user inputs his data. If it isn't a number, it returns false and goes into the while loop.
    {
        getchar();
        puts("Please enter a number.");
    }
    for (j = 0; j < amount; j++) // Loops through the specified amount
    {
        DAQmxErrChk (DAQmxCreateTask("",&taskHandle));
        DAQmxErrChk (DAQmxCreateAIVoltageChan(taskHandle,"Dev1/ai0","",DAQmx_Val_Cfg_Default,1.0,10.0,DAQmx_Val_Volts,NULL));
        DAQmxErrChk (DAQmxCfgSampClkTiming(taskHandle,"",10000.0,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,1000));

        /*********************************************/
        // DAQmx Start Code
        /*********************************************/
        DAQmxErrChk (DAQmxStartTask(taskHandle));

        /*********************************************/
        // DAQmx Read Code
        /*********************************************/

        DAQmxErrChk (DAQmxReadAnalogF64(taskHandle,1000,10.0,DAQmx_Val_GroupByChannel,i_array,1000,&read,NULL));

        printf("Updating... ");
        printf("Data point %d has %f",j, i_array[j]); // Displays the voltage set number of times
        printf(" volts\n");
        Sleep(200); // ms pause between each reading

        if( taskHandle!=0 )
        {
            /*********************************************/
            // DAQmx Stop Code
            /*********************************************/
            DAQmxStopTask(taskHandle);
            DAQmxClearTask(taskHandle);
        }
    }

    if(j==amount)
    {
        printf("\nVoltage readings aquired. Please specify a filename so the data can be saved.\n");
        goto Save;
    }


Save:
    printf("\nPlease enter a filename...\n");
    gets(filename);
    printf("Name is: ");
    puts(filename);
    save_file = fopen(filename,"w");
    printf("File made");

        for (j = 0; j < amount; j++)
        {           
            fwrite(&i_array[j], sizeof(j), j, save_file);
                    printf("Saving...\nSaved.");
        }       

    getchar();
    free((void*) i_array);
Error:
    if( DAQmxFailed(error) )
        DAQmxGetExtendedErrorInfo(errBuff,2048);    

    if( DAQmxFailed(error) )                
        printf("DAQmx Error: %s\n",errBuff);

    return 0;
}

I'll explain my program. It uses a NI USB 6211 to measure inputs and outputs, and then displays it. This program is used to measure the amount of voltage coming into the ADC. It reads it just fine and my dynamic array also works as it should. Now, when it comes down to the actual writing the file:

for (j = 0; j < amount; j++)
{           
    fwrite(&i_array[j], sizeof(j), j, save_file);
    printf("Saving...\nSaved.");
}

I'm getting the error "Null pointer was passed for a required parameter". Now, I KNOW this is coming from my fwrite code block, but i've tried so many different ways of writing the code, but it just doesn't want to comply. I've tried using pointers and also not, it just won't write the data. (When I say data, I mean the voltage reading).


Solution

  • When you initialize i_array = (float64*) malloc (j * sizeof (int)) there are two issues:

    1. j is uninitialized. It has a garbage value. When you multiply it by sizeof (int) you are multiplying garbage. This will cause the memory allocation to have undefined results. You need to read amount first, then initialize using amount rather than j as the multiplier.
    2. You've declared i_array as a pointer to float64. In that case, your array elements need to be float64, not int.

    So: after you get amount from input, allocate your array:

    i_array = malloc (amount * sizeof (float64));
    

    A couple of things: first, it is considered un-C-like to cast the return value of malloc; second, do not use gets, it is nonstandard as of C11. Use fgets instead:

    fgets (filename, sizeof (filename), stdin);