首页 > 解决方案 > 添加到链表时,节点地址一直相互覆盖

问题描述

我正在尝试使用任务列表并将输出通过管道传输到我的代码并解析每一行以创建每个进程的节点。我稍后将通过它们进行过滤,但这还没有在代码中。我在使用LIST. 我structs为这个程序实现了 3 个:(LIST第一个节点的头,最后一个节点的后部和列表中节点数的计数),NODE(指向PROCESS_INFO下一个的指针和指针NODE),PROCESS_INFO(用于进程名称、PID、内存使用的 4 个字符指针和处理器时间)。我曾经printf跟踪我的代码,在我将它们添加到链接列表之前,一切似乎都正常工作。每个节点的地址不同,但它似乎总是覆盖列表中的最后一个,而不是将节点的新地址添加到前一个节点的 next* 中。

我很肯定我的算法是正确的,这与我多次使用的算法相同,只是数据不同。我的malloc函数有动态检查,以防它们出错,并且我已经检查并使用了我的指针,以防我错过了某种取消引用,但是如果我改变任何东西,我会得到错误,所以我认为这些问题不够有趣。

我唯一能想到的问题是所有这些都驻留在函数的循环中(我在某个地方读到堆栈上的指针不记得它们的地址?)。我必须改变什么来解决这个问题?我已将所有内容移至主目录,但没有任何改变。

结构定义:

typedef struct processInfo{
    char *pName;
    char *processId;
    char *memUsage;
    char *cpuTime;
}PROCESS_INFO;

typedef struct node{
    PROCESS_INFO* data;
    struct node* next;
}NODE;

typedef struct li{
    int num;
    NODE* head;
    NODE* rear;
}LIST;

主功能:

int main()
{
    LIST* list;
    list = buildList();
    printList(list);
}

列表功能:

//function that creates a new list and returns it as null
LIST* createList()
{
    LIST* newListPtr;
    newListPtr = (LIST*)malloc(sizeof(LIST));

    if (newListPtr)
    {
        newListPtr->num = 0;
        newListPtr->head = NULL;
        newListPtr->rear = NULL;
    }
    return newListPtr;
}

//function that creates the struct for the information of the process
PROCESS_INFO* createPinfo(char* name, char* pid, char* kb, char* cTime)
{
    PROCESS_INFO* pInfoPtr;
    pInfoPtr = (PROCESS_INFO*)malloc(sizeof(PROCESS_INFO));

    if (pInfoPtr)
    {
        pInfoPtr->pName = name;
        pInfoPtr->processId = pid;
        pInfoPtr->memUsage = kb;
        pInfoPtr->cpuTime = cTime;
    }
    return pInfoPtr;
}

//function to create new node and set its data
NODE* createNode(PROCESS_INFO* dataPtr)
{
    NODE* nodePtr;
    nodePtr = (NODE*)malloc(sizeof(NODE));

    if (nodePtr)
    {
        nodePtr->data = dataPtr;
        nodePtr->next = NULL;
    }
    return nodePtr;
}

//Get process information node via the path
PROCESS_INFO* parseInfoFromPath (char str[])
{
    char *pName;
    char *processId;
    char *memUsage;
    char *time;
    char *parse;

    parse = strtok(str, " ");
    pName = parse;

    parse = strtok(NULL, " ");
    processId = parse;

    parse = strtok(NULL, " "); //Console
    parse = strtok(NULL, " "); //session
    parse = strtok(NULL, " "); //memory
    memUsage = parse;

    parse = strtok(NULL, " ");
    parse = strtok(NULL, " ");
    parse = strtok(NULL, " ");
    parse = strtok(NULL, " "); //CPUTIME
    time = parse;

    PROCESS_INFO* pInfoPtr;
    pInfoPtr = createPinfo(pName, processId, memUsage, time); 

    return pInfoPtr;
}

BuildList() 函数,我似乎得到了语义错误:

LIST* buildList()
{
    FILE *fp;
    char path[PATH_MAX];

    fp = popen("tasklist /v /fi \"STATUS eq running\" /nh ", "r");
    if (fp == NULL)
    {
        printf( "CreateProcess failed (%d).\n", GetLastError() );
        return;
    }

    LIST* list_;
    PROCESS_INFO* p;
    NODE* n;
    list_ = createList();

    while (fgets(path, PATH_MAX, fp) != NULL)
    {
        if (path != NULL)
       {
            //create the process info struct
            p = parseInfoFromPath(path);

            //create the node
            n = createNode(p);

            //add node to list
            //if empty list set as head
            if (list_->head == NULL){
                list_->head = n;
            }
            //otherwise set last->next to point to the new node
            else {
                list_->rear->next = n;
            }

            //rear points to last node
            list_->rear = n;
            (list_->num)++;

        }

    }
    //They always print out the same data!!!!
    printf("\nIn Loop: Head Node name: %s", list_->head->data->pName); 
    printf("\t\tIn Loop: Read Node name: %s", list_->rear->data->pName);
    return list_;
}

标签: cmemorylinked-list

解决方案


您不会为找到的每个输入字段复制字符串。相反,您将指针保存在path缓冲区中,每次执行时都会被覆盖fgets。尝试strdup使用createPinfo

PROCESS_INFO* createPinfo(char* name, char* pid, char* kb, char* cTime)
{
    PROCESS_INFO* pInfoPtr;
    pInfoPtr = (PROCESS_INFO*)malloc(sizeof(PROCESS_INFO));

    if (pInfoPtr)
    {
        pInfoPtr->pName = strdup(name);
        pInfoPtr->processId = strdup(pid);
        pInfoPtr->memUsage = strdup(kb);
        pInfoPtr->cpuTime = strdup(cTime);
    }
    return pInfoPtr;
}

此外,由于strdup分配了堆内存,所以不要忘记添加一个函数来释放内存并在每次从列表中删除某些内容时调用它。例如:

void destroyPinfo(PROCESS_INFO* pInfoPtr)
{
    if (pInfoPtr)
    {
        free(pInfoPtr->pName);
        pInfoPtr->pName = NULL;

        free(pInfoPtr->processId);
        pInfoPtr->processId = NULL;

        free(pInfoPtr->memUsage);
        pInfoPtr->memUsage = NULL;

        free(pInfoPtr->cpuTime);
        pInfoPtr->cpuTime = NULL;
    }
}

您可能希望像您一样NULL检查结果(只要您了解基本概念,我就懒得将其添加到答案中)。strdupmalloc


推荐阅读