从C函数返回链表结构

时间:2014-11-24 17:09:13

标签: c struct

我已经达成了这个问题。我有一个相当大的C程序,当它应该返回时,它正在给我分段错误。

    struct customer{
    char *name;
    int custID;
    double credit;
    char *address;
    char *state;
    char *zip;
};
typedef struct customer customer;

struct custNode{
    customer *customer;
    struct custNode *next;
};
typedef struct custNode custNode;

// 。

custNode *customerList = (custNode *)malloc(sizeof(custNode));
readDatabase(fp,customerList);

因此,读取数据库的功能是从同一目录中的文件中读取字符串,并从中创建一个custNodes的链接列表。似乎我的代码没有正确地将custNodes附加到列表的前面,我不知道为什么。它在readDatabase函数的return语句中断开。

void attachCustNode(custNode *head, customer *target){
    if(!target || !head){
        printf("\nTarget or Head is NULL!!!\n");
    }
    custNode *temp = malloc(sizeof(custNode));
    temp->customer = target ;

    if(!head->customer){
        printf("building new list\n");
        temp->next = head;
        *head = *temp;
    }
    else{
        printf("ELSE attaching to front\n");
        temp->next = NULL;
        *head = *temp;
    }
    return;
}



void readDatabase(FILE *fp , custNode *result){ //reads the database file for the customers
    printf("reading database, creating structures.\n");
    int i , size;
    size_t fSize; //getline wants size_t ... dumb.
    char *buff,*tok;
    unsigned int error = 1;
    char delim[3] = "|\"";
    delim[2] = '\0';

    result->customer = NULL;
    result->next = NULL;

    fseek(fp, 0L, SEEK_END);
    size = ftell(fp);
    fSize = size;
    fseek(fp , 0 , SEEK_SET) ; //get size of file, reset fseek
    printf("database of  size %d \n", size);
    buff = malloc( (sizeof(char)*size)+1);
    /*
    printf("Buffer is %s and error is %d  \n", buff, error);
    if( error <= 0 ){
        printf("getline fell and couldn't get up in %s on line %d\n", __FILE__ , __LINE__);
        break;
    }
    */
    //int len;
    while( error > 0 ){
        error = getline(&buff, &fSize, fp);
        if( error < 0 ){
            printf("breaking loop\n");
            break;
        }
        customer *temp = (customer *)malloc(sizeof(customer));
        tok = strtok(buff , delim);
        temp->name = tok;
        tok = strtok(NULL, delim);
        temp->custID = atoi(tok); ///int atoi(const char *nptr);
        tok = strtok(NULL, delim);
        temp->credit = atof(tok); //double atof(const char *nptr);
        //printf("added %lf to temp orderNode\n",temp->credit); //%f prints doubles.
        tok = strtok(NULL, delim);
        temp->address = tok;
        tok = strtok(NULL, delim);
        temp->state = tok;
        tok = strtok(NULL, delim);
        temp->zip = tok;
        attachCustNode(result,temp);
    }
    return ;
}

提前感谢您的帮助。

EDIT。我已经在这个github gist中发布了我的代码以使其更容易,它仍然由于某种原因不会退出该函数。我在第148行添加了strdup函数,如响应所示,但由于某种原因,它仍然没有返回。

https://gist.github.com/DavidAwad/006489d0648474a1a7e5

5 个答案:

答案 0 :(得分:3)

我认为这段很小的代码没有做你想做的事情:

result->customer == NULL;
result->next == NULL;

也许

result->customer = NULL;
result->next = NULL;

?然后 attachCustNode()中的if-Statement将起作用,并且应该添加列表项。

答案 1 :(得分:3)

attachCustNode中使用的逻辑有问题。

head始终指向内存中的相同位置。我们说它的值是H

当列表为空时:

head       =   H
temp->next =   H
*head = *temp;

这意味着:

head       =   H
head->next =   H

您需要的是

head->next =   NULL

此时,temp是内存泄漏。

当列表不为空时:

temp->next = NULL;
*head = *temp;

这使得

head       =   H
head->next =   NULL

此时,temp是内存泄漏。

用于确定列表是否为空的策略是错误的。而不是

if(!head->customer){

你应该重构你的代码,甚至不用担心列表是否为空。

这是重构的代码:

custNode* attachCustNode(custNode* head, customer *target){

    custNode *temp = malloc(sizeof(custNode));
    temp->customer = target;

    // No matter what head is temp is now the head.
    temp->next = head;
    return temp;
}

稍微重构readDatabase。返回新创建的列表,而不是传递指针。

custNode* readDatabase(FILE *fp){ //reads the database file for the customers
    custNode *result = NULL;

    // Your code
    // ....

    while( error > 0 ){
       // Your code
       // ....
       result = attachCustNode(result, temp);
    }

    return result;
}

重构main以说明对readDatabase的更改。

custNode *customerList = readDatabase(fp);

<强>更新

其中一些线路不正确。您指向从函数返回后无效的内存。您需要为字符串分配内存并使用strcpy或仅使用strdup

    customer *temp = (customer *)malloc(sizeof(customer));
    tok = strtok(buff , delim);
    temp->name = tok;               // NOT GOOD
    tok = strtok(NULL, delim);
    temp->custID = atoi(tok);
    tok = strtok(NULL, delim);
    temp->credit = atof(tok);
    tok = strtok(NULL, delim);
    temp->address = tok;           // NOT GOOD
    tok = strtok(NULL, delim);
    temp->state = tok;             // NOT GOOD
    tok = strtok(NULL, delim);
    temp->zip = tok;               // NOT GOOD

使用:

    temp->name = strdup(tok);

对成员addressstatezip进行类似的更改。

答案 2 :(得分:2)

我至少看到一个问题: strtok返回的指针是buff(读缓冲区)的指针 这些都保存在每个客户结构中。 但是在下一次读取(getline)时,输入缓冲区(buff)会被清除掉, 并且保存在客户结构中的指针现在指向谁知道什么。

您需要为每个名称,地址,状态,zip分配内存, 或者在客户结构中将它们作为char数组。

我不知道你是如何得到段错误的, 但有一种方法是当你自由()buff(你应该这样,即使它没有显示) 所有客户结构中的所有指针都将变为无效。

答案 3 :(得分:0)

不要这样做

   tok = strtok(NULL, delim);
    temp->address = tok;

DO

  tok = strtok(NULL, delim);
    temp->address = strdup(tok);

strtok正在返回指向buff中某个位置的指针,该指针可能会或可能不会继续存在。 Strdup会将你的字符串副本复制到malloced内存中 - 你必须释放它

答案 4 :(得分:0)

答案实际上与此无关。 :/我正在使用getline函数,它被设置为unsigned int所以它从来都不是负面的。