如何在C中正确指向结构成员?

如何在C中正确指向结构成员?,c,csv,struct,complex-numbers,C,Csv,Struct,Complex Numbers,我在C中创建了一个非常简单的“csvread”函数,它将按照暗示从CSV文件中读取。(在本例中,为了进行测试,我稍微编辑了它,以便可以将虚拟数据写入文件,然后读取它)。我创建了一个结构来存储复杂的数据。但是,我的psuedo csv文件只包含我需要使用的数据的真实部分。我想将此数据存储到“data.real”数组中。然而,我似乎无法记下正确的语法。(尽管,不可否认,这可能更像是一个完全理解指针的问题,而不仅仅是语法问题)。任何帮助都将不胜感激 在下面的代码中,我知道以下函数调用是问题所在: c

我在C中创建了一个非常简单的“csvread”函数,它将按照暗示从CSV文件中读取。(在本例中,为了进行测试,我稍微编辑了它,以便可以将虚拟数据写入文件,然后读取它)。我创建了一个结构来存储复杂的数据。但是,我的psuedo csv文件只包含我需要使用的数据的真实部分。我想将此数据存储到“data.real”数组中。然而,我似乎无法记下正确的语法。(尽管,不可否认,这可能更像是一个完全理解指针的问题,而不仅仅是语法问题)。任何帮助都将不胜感激

在下面的代码中,我知道以下函数调用是问题所在:

 csvread("test.txt", &data->real);
然而,我已经尝试了第二个参数的多种变体,这是我唯一可以编译的

我已经让我的代码在数据不是结构的情况下工作。例如,如果声明了数据:

double data[10];
所以,正如您(希望)看到的,我在理解指向结构成员的指针方面遇到了困难

这是我的密码:

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

#define SIZE 10

typedef struct Complex
{
   double real;
   double imag;
}complex;

void csvread(char *filename, double *data_out);

int main(void)
{
   complex *data;
   csvread("test.txt", &data->real);
   for(int i = 0; i<SIZE; i++)
   {
       printf("%f\n", data[i].real);
   }
}  

// This function reads csv files
void csvread(char *filename, double *data_out)
{
    FILE *file;
    char *no_commas; // character buffer to store strings without comma parse
    double *buffer; // character data converted to double type
    const char comma[2] = ",";
    char *csv;
    char *token;
    int file_size;
    int i = 0;

    // Read CSV file
    file = fopen(filename,"w+"); // change to "r" if read only
    if(file == NULL)
    {
        printf("\n The file requested cannot be found.");
        exit(1);
    }
    fprintf(file, "%s", "1.18493,0.68594,-7.65962,9.84941,10.34054,7.86571,0.04500,11.49505,-8.49410,-0.54901"); 
    fseek(file, 0, SEEK_SET); // return to beginning of the file

    // Find the file size in bytes 
    fseek(file, 0, SEEK_END); // go to end of file
    file_size = ftell(file);
    fseek(file, 0, SEEK_SET); //  return to beginning of file

    // Allocate buffer memory
    no_commas = malloc((file_size) * sizeof(char));
    buffer = malloc((file_size) * sizeof(double));

    if (no_commas == NULL || buffer == NULL)
    {
        printf("Failed to allocate memory when reading %s.\n\n", filename);
        exit(1);
    }

    while ((csv = fgets(no_commas, (file_size + 1), file)) != NULL) // fgets is used as file has no newline characters
    {
        // Remove Commas from string
        token = strtok(csv, comma);
        while (token != NULL)
        {
            //printf("%s\n", token); 
            buffer[i] = atof(strdup(token));
            token = strtok(NULL, comma);
            //printf("%f\n", buffer[i]); 
            i++;
        }
    }
    data_out = buffer;
    fclose(file);
    free(no_commas);
    free(buffer);
}
预期产出:

 1.18493
 0.68594
-7.65962
 9.84941
10.34054
 7.86571
 0.04500
11.49505
-8.49410
-0.54901

编辑:感谢大家的评论和帮助!我认为约翰尼·莫普的回答最有帮助。这个问题演变成了更多关于分配内存的问题,而不是预期的问题,这最终是非常有用的信息

在java中,这将被视为一个NullPointerException,在C中不会出现这种错误,但这也是一种责任。在C中延迟空指针(正如您所做的那样)可能会有多种响应方式。正如评论中所说,您需要分配
数据
指针

complex *data = malloc(sizeof(complex));
您还应该释放分配给
malloc
的内存,因此在代码末尾将程序状态返回操作系统之前(您没有这样做),您应该执行以下操作:

free(data);
我不确定您的csvread是如何工作的,但它可能只使用一系列复杂的结构。下面的代码分配了10个复数来初始化它们,在
csvread
函数中,您可能需要做一些修改来迭代它们,正如您所展示的那样,使用简单的数组声明,您的代码可以工作

complex *data = calloc(10, sizeof(complex));

上面的代码分配了10个复杂结构,指针指向第一个分配的结构。要对它们进行迭代,您可以使用数字(例如
数据[0].real=4
)或使用指针算法对它们进行索引。我有一种强烈的感觉,您将不得不修改在
csvread
函数中迭代
数据输出
指针的方式。

您不能只分配
真实的
部分。您需要分配整个结构-即使您只是使用
real
部分。如果您使用的是数组,则如下所示:

complex data[10];
data[0].real = 1.0;
data[1].real = 2.0;
// etc..
但是您必须动态地分配
复杂的
数组,因为文件中的项目数在时间之前是未知的(我假设)。您可以一次分配一个
复杂的
对象,同时调整数组的大小

// Prototype has changed to pointer-to-pointer complex
// Return value is the number of items read
int csvread(char *filename, complex **data);

int main(void)
{
   complex *data = NULL;
   int num_records = csvread("test.txt", &data);
   for(int i = 0; i < num_records; i++)
   {
       printf("%f\n", data[i].real);
   }
   free(data);
}  

// This function reads csv files
int csvread(char *filename, complex **data_out)
{
    // This will be used to avoid always having to dereference
    // the data_out parameter
    complex *array = NULL;
    int num_records = 0;

    while (1) {
        double value = // read a value from the file.....
        // If error or end of file break out of loop

        // Allocate space for another complex object
        array = realloc(array, sizeof(complex) * (num_records + 1));
        if (NULL == array) // handle error

        // Store just the real part
        array[num_records].real = value;
        // Also, you can initialize imag here but not required
        array[num_records].imag = 0;
        num_records += 1;
    }

    // Store and return
    *data_out = array;
    return num_records;
}

您的问题是,
数据
未初始化,因此指向无效位置。您提出的问题不正确。为了指出某件事,这件事必须存在。虽然您的
数据
根本没有分配。csv文件是否只包含真实的部分?无论如何,原型应该是
void csvread(char*filename,complex*data\u out)
如果在调用
csvread
之前分配数组,或
void csvread(char*filename,complex**data_out)
如果在
csvread
@DaBler yes中分配数据,则csv文件仅包含真实部分。我将尝试更新您所说的代码。@EugeneSh。注意。正如ranu所说,我已经编辑了我的代码,但是我仍然得到了0.00000的输出。感谢编辑,我将向您展示我的csv读取代码,正如我在Johnny的回答中所说的。这对我来说是有意义的,但我还需要存储虚构的数据。我想如果我要重写csvread,我可以添加一个参数来处理这个问题。我会更新我的帖子来展示我是如何阅读的。这是非常基本的。@user15我不知道你所说的存储虚拟数据是什么意思。您的意思是在csv文件中吗?有多个csv文件。一个文件包含实数据集,而另一个文件包含虚数据集。我最终需要读这两本书。对于我的csvread函数,我本来打算调用它两次,以便将两个数据集都放在一个结构中。@user15您可以这样做。当你第二次调用它时,不要
realloc
任何东西。只需将数据存储在
imag
中即可。或者修改以同时解析这两个文件。好的,谢谢您的帮助!你认为用我目前拥有的东西可以修改读取两个文件,还是建议完全重写我的函数(忽略写入文件部分)?我还有一个特例,我有一个只有实值的数据集。你会建议为此编写一个单独的函数吗?还是你认为这是一个简单的加法?
// Prototype has changed to pointer-to-pointer complex
// Return value is the number of items read
int csvread(char *filename, complex **data);

int main(void)
{
   complex *data = NULL;
   int num_records = csvread("test.txt", &data);
   for(int i = 0; i < num_records; i++)
   {
       printf("%f\n", data[i].real);
   }
   free(data);
}  

// This function reads csv files
int csvread(char *filename, complex **data_out)
{
    // This will be used to avoid always having to dereference
    // the data_out parameter
    complex *array = NULL;
    int num_records = 0;

    while (1) {
        double value = // read a value from the file.....
        // If error or end of file break out of loop

        // Allocate space for another complex object
        array = realloc(array, sizeof(complex) * (num_records + 1));
        if (NULL == array) // handle error

        // Store just the real part
        array[num_records].real = value;
        // Also, you can initialize imag here but not required
        array[num_records].imag = 0;
        num_records += 1;
    }

    // Store and return
    *data_out = array;
    return num_records;
}
// Create a function that just opens and reads a file
char *load_file(const char *path) {
    // TODO:
    // Open the file and read entire contents
    // return string with contents

    // If path is NULL, must return NULL

    // Must return NULL if file does not exist
    // or read error
}

// Use this function instead of strok so you 
// can use on 2 string simultaneously
double get_next_value(char **string)
{
    char *start = *string;
    char *end   = *string;

    // Loop until comma or end of string
    while (*end && *end != ',') end++;
    // If comma, terminate and increment
    if (*end) *end++ = 0;
    // Update for next time
    *string = end;
    return atof(start);
}

// This function reads csv files
int csvread(char *real_filename, char *imag_filename, complex **data_out)
{
    // This will be used to avoid always having to dereference
    // the data_out parameter
    complex *array = NULL;
    int num_records = 0;

    // Load each file into a string. May be NULL
    char *real_data_orig = load_file(real_filename);
    char *imag_data_orig = load_file(imag_filename);

    // Temporary copies of the pointers. Keep the originals
    // to free() later. These will be modified
    char *real_data = real_data_orig;
    char *imag_data = imag_data_orig;

    while (1) {
        // Check for data. Make sure pointer is not
        // NULL and it is still pointing to something
        // that is not '\0'
        bool has_real = real_data && *real_data;
        bool has_imag = imag_data && *imag_data;

        // No data? Done.
        if (!has_real && !has_imag) break;

        // Allocate space for another complex object
        array = realloc(array, sizeof(complex) * (num_records + 1));
        if (NULL == array) // handle error

        // Store the real part (if there is one)
        if (has_real) {
            array[num_records].real = get_next_value(&real_data);
        }
        // Store the imag part (if there is one)
        if (has_imag) {
            array[num_records].imag = get_next_value(&imag_data);
        }
        num_records += 1;
    }

    // Free the file contents
    free(real_data_orig);
    free(imag_data_orig);

    // Store and return
    *data_out = array;
    return num_records;
}