函数似乎 return 正确的值,但外部调用者永远不会在 C 中获取它

Function seems to return the correct value, but the outside caller never gets it in C

我使用链表实现了一个队列。我还创建了一个 getter 来读取此队列中任何条目的数据。当我从测试人员调用此函数时,我发现作为队列内条目值返回的值与在 getter 中读取的值不同。

struct entry{
    double data;
    attribute_value time_stamp;
    struct entry* next;
};


typedef struct queue_struct{
    struct entry* front;
    struct entry* end;
    int size;
} queue;

下面的getter接受队列的一个条目和returns数据结构变量的值,如果当前条目不为空:

double get_data(struct entry *current){
    // The value is correct here
    printf("!!!!!!!!!!!!! %lf\n", current->data);
    if(current) return current->data; 
    return 0;
}

我使用这个助手来获取队列的第一个条目:

struct entry* get_front(queue *Q){
    return Q->front;
}

测试人员来了。它创建一个队列(它简单地为其分配 space 并分配 first = NULL、end = NULL 和 size = 0)。然后它将值 10 推入队列。 (忽略零!它与数据没有任何关系)。然后,它通过从第一个元素开始并打印 "data" 变量直到遇到 NULL 元素来成功打印队列。然后,我要求它打印队列中第一个 entry/element 的数据。这是我得到错误值的地方。

void test_queue_push(bool enable_print){
    printf(TESTING, "Testing push in queue.c");
    queue* Q = construct_queue();

    push(Q, 10, 0);
    if(enable_print) print_queau(Q); // This prints the queue correctly!

    // The wrong value is printed here!
    printf("GET DATA: %lf\n", get_data(get_front(Q))); 
}

此测试打印出以下内容:

10.000000 ->                        // This is result of print_queue
!!!!!!!!!!!!! 10.000000             // This is data of first entry printed INSIDE the getter function itself
GET DATA: 0.000000                  // This is the returned data of first entry, printed inside the tester

我不明白为什么我没有得到第二行和第三行的值“10.0000”。

I just tried using "long long int" instead of "double" for the entry's data variable and all of the other functions. The error disappears if I use a different data type. No idea why.

打印队列也使用了get_data函数,打印出来的第一行反映了print_queue里面的get_data工作正常。这是函数:

void print_queau(queue* Q) {
    struct entry* temp = get_front(Q);
    while(temp != NULL) {
        printf("%lf -> ", get_data(temp));
        temp = get_next(temp);
    }
    printf("\n");
}

以防万一,推送函数如下所示:

void push(queue* Q, double input, attribute_value time_stamp){
    if(Q){ //if Queue exists
    struct entry* in;   //create a new entry object
        if(in = calloc(1, sizeof(struct entry))){ //if allocating space for the entry object succeeds
            Q->size = Q->size + 1;
            in->data = input; //enter the input as its current data
            in->next = NULL; //set next to null because the end of the queue can have no next entry that follows it
            in->time_stamp = time_stamp; //set the time stamp to the Power On Hours on the system

            if(get_front(Q) == NULL && get_end(Q) == NULL){  //if front and end of the queue have not yet been set
                set_front(Q, in); //then this entry is both the front
                set_end(Q, in); //and the end
                return;
            }
            set_next(get_end(Q), in); //next value of the entry at the end is now our new entry
            set_end(Q, in);
            //printf("The End is: %i\n", Q->size);
        }
    }
}

构造队列如下所示:

/*Constructor for the Queue structure instance
    @param none
    @return pointer to queue or NULL pointer in case of memory allocaion failure
*/
queue* construct_queue(){
    queue* Q;
    if(Q = calloc(1, sizeof(queue))){ 
        Q->front = NULL;  //at first the queue does not have any entries
        Q->end = NULL;    //therefore it has no front and no end
        Q->size = 0;      //its size starts off at zero to indicate that there are no entries.
    }
    if(Q == NULL){
        fprintf(stderr, "Ran out of memory when allocating memory for queue in construct_queue in queue.c\n");
    }
    return Q;
}

我使用以下代码来构建上面的代码:https://gist.github.com/mycodeschool/7510222

有很多缺失的代码需要重建。这段代码仔细确保所有函数在使用前都已声明,似乎可以正常工作:

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

typedef int attribute_value;

#define TESTING "%s\n"

struct entry
{
    double data;
    attribute_value time_stamp;
    struct entry *next;
};

typedef struct queue_struct
{
    struct entry *front;
    struct entry *end;
    int size;
} queue;

double get_data(struct entry *current);
queue *construct_queue(void);
struct entry *get_front(queue *Q);
struct entry *get_end(queue *Q);
void print_queau(queue *Q);
void push(queue *Q, double input, attribute_value time_stamp);
void test_queue_push(bool enable_print);
struct entry *get_next(struct entry *curr);
void set_front(queue *Q, struct entry *in);
void set_end(queue *Q, struct entry *in);
void set_next(struct entry *E, struct entry *in);

void set_front(queue *Q, struct entry *in)
{
    if (Q != 0)
        Q->front = in;
}

void set_end(queue *Q, struct entry *in)
{
    if (Q != 0)
        Q->end = in;
}

void set_next(struct entry *E, struct entry *in)
{
    if (E != 0)
        E->next = in;
}

struct entry *get_next(struct entry *curr)
{
    if (curr != 0)
        return curr->next;
    return 0;
}

double get_data(struct entry *current)
{
    if (current)
    {
        printf("!!!!!!!!!!!!! %lf\n", current->data);
        return current->data;
    }
    return 0;
}

struct entry *get_end(queue *Q)
{
    return Q->end;
}

struct entry *get_front(queue *Q)
{
    return Q->front;
}

void test_queue_push(bool enable_print)
{
    printf(TESTING, "Testing push in queue.c");
    queue *Q = construct_queue();

    push(Q, 10, 0);
    if (enable_print)
        print_queau(Q);


    printf("GET DATA: %lf\n", get_data(get_front(Q)));
}

void print_queau(queue *Q)
{
    struct entry *temp = get_front(Q);
    while (temp != NULL)
    {
        printf("%lf -> ", get_data(temp));
        temp = get_next(temp);
    }
    printf("\n");
}

void push(queue *Q, double input, attribute_value time_stamp)
{
    if (Q)
    {
        struct entry *in;
        if ((in = calloc(1, sizeof(struct entry))) != 0)
        {
            Q->size = Q->size + 1;
            in->data = input;
            in->next = NULL;
            in->time_stamp = time_stamp;

            if (get_front(Q) == NULL && get_end(Q) == NULL)
            {
                set_front(Q, in);
                set_end(Q, in);
                return;
            }
            set_next(get_end(Q), in);
            set_end(Q, in);
        }
    }
}

queue *construct_queue(void)
{
    queue *Q;
    if ((Q = calloc(1, sizeof(queue))) != 0)
    {
        Q->front = NULL;
        Q->end = NULL;
        Q->size = 0;
    }
    if (Q == NULL)
    {
        fprintf(stderr, "Ran out of memory when allocating memory for queue in construct_queue in queue.c\n");
    }
    return Q;
}

int main(void)
{
    test_queue_push(true);
    return 0;
}

编译:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
>     -Werror queue.c -o queue
$

这是 Mac OS X 10.10.4 上的 GCC 5.1.0,选项设置繁琐且没有警告。 'prototypes' 选项确保函数在定义或使用之前被声明——或者是 static 函数。我这里什么都没做static;我通常在只有一个源文件时这样做。

示例输出:

Testing push in queue.c
!!!!!!!!!!!!! 10.000000
10.000000 -> 
!!!!!!!!!!!!! 10.000000
GET DATA: 10.000000

可以假设问题要么是缺少一个或多个函数原型,要么是其中一个函数存在错误。请注意,我修复了 get_data() 中的代码,因此如果 current 指针为 NULL,它不会崩溃 — 无论 current 是否为 NULL,您的代码都试图打印 current->data 中的值是否为 null(即使它随后检查了值 current — 有点太晚了)。