在函数

时间:2017-10-10 13:17:27

标签: c list structure singly-linked-list

我目前正在尝试学习链接列表如何作为个人项目。我理解核心概念,并且我一直在尝试将其实现为c。我的程序看起来应该可以工作,请记住我还是编程的新手:D

我创建了一个名为head的structer指针。 head将指向linked_list中的第一个节点,startPtr将包含head的地址。每次调用函数add时,都会创建一个新节点并在内存中分配一些空间,然后先前创建的节点将指向新节点。

我知道程序崩溃的地方,但我明白为什么?它汇编得很好。

我的代码崩溃了

(*prevNode)->link = newNode; 

这是我看到此代码的方式: 我将双指针startPtr传递给函数add。然后我使用malloc创建了一个新节点。接下来我deference startPtr(在函数中称为prevNode),它应该包含head的内存地址....对吗?然后我用“ - >”表达式指向头部内部的结构指针称为链接。

该计划刚刚结束,我不明白为什么。我查看了其他链表c代码,但大多数都不使用双指针,只是声明全局结构和指针。我使用GCC作为我的编译器。

任何人都知道为什么会这样吗?

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


// STRUCTURES

struct node
{
    int data;
    struct node *link;
}*head;

void add( int, struct node ** );


int main()
{   
    struct node *head;
    struct node **startPtr;
    startPtr = head;
    struct node *nodePtr;
    int userInput;
    int inputData;


    do{
    printf( "\n\n1: enter new node\n" );
    printf( "2: Print Nodes\n" );
    printf( "\n\nEnter: " );
    scanf( "%d", &userInput );
        if ( userInput == 1 )
        {
            printf( "\n\nEnter data:");
            scanf("%d", &inputData );
            add( inputData, startPtr );
        }

    }while( userInput == 1 );

    // printing linked list
    nodePtr = head->link;
    while( nodePtr->link != NULL )
    {
        printf( "%d\n", nodePtr->data);
        nodePtr = nodePtr->link;
    }
    printf( "%d\n", nodePtr->data);
    return 0;

}// END main()

void add( int num, struct node **prevNode )
{
    // assigning memory for a new node
    struct node *newNode = malloc( sizeof( struct node ) );
    (*prevNode)->link = newNode;        
    newNode->data = num;        
    newNode->link = NULL;        
    prevNode = &newNode;
}// END add()

另外,我还有一个我无法在网上找到并回答的问题。当我创建一个指向结构的指针,例如struct node * ptr;。结构指针我的默认存储它自己的地址。我自己的意思是结构,所以如果我打印ptr它会输出结构ptr的地址吗?

3 个答案:

答案 0 :(得分:2)

要在这里解压缩很多......这些是未初始化的,然后你将指针别名而不是指向一个地址,所以你真的没有指针指向你有2个相同指针的指针

struct node *head;
struct node **startPtr;
startPtr = head;
struct node *nodePtr;

可能是这样的:

struct node *head = NULL;
struct node **startPtr = &head;
struct node *nodePtr = NULL;

将是一个更好的开始...然后在C中你可以解析一个NULL指针,所以你必须首先检查是否有可能是空指针...注意这不会检查未初始化的垃圾值,哪个局部变量可以是:

if(startPtr && *startPtr)
{
 // now you know you can deref startPtr twice,  
 // once to a pointer to an object (which might be null)
 // then after then && you can deref to an actual object
}

答案 1 :(得分:1)

struct node *head;

从未初始化

startPtr = head;

初始化为未初始化;除此之外,你的整个程序都是未定义的。

答案 2 :(得分:1)

除了这个错字

startPtr = head;
           ^^^^

必须在哪里

startPtr = &head;
           ^^^^^  

代码有几个问题。

第一个是标头最初未初始化。因此,取消引用此指针会导致未定义的行为。

第二个问题是这个循环

do{
printf( "\n\n1: enter new node\n" );
printf( "2: Print Nodes\n" );
printf( "\n\nEnter: " );
scanf( "%d", &userInput );
    if ( userInput == 1 )
    {
        printf( "\n\nEnter data:");
        scanf("%d", &inputData );
        add( inputData, startPtr );
    }

}while( userInput == 1 );

逻辑错误地构建。例如,如果用户输入的某个数字不等于1或2,则程序将在退出循环后尝试输出列表。

第三个是最初的头可以等于null。所以这个语句在函数中

(*prevNode)->link = newNode;

再次调用未定义的行为,而且如果*prevNode不等于NULL,则所有早期附加的节点都将丢失,因为它的引用link被覆盖。

该功能可以按以下方式查看

int add( struct node **head, int data )
{
    struct node *newNode = malloc( sizeof( struct node ) );
    int success = newNode != NULL;

    if ( success )
    {
        newNode->data = data;
        newNode->link = *head;
        *head = newNode;
    }

    return success;
}