【问题标题】:Using double pointers in functions [duplicate]在函数中使用双指针[重复]
【发布时间】:2017-10-10 13:17:26
【问题描述】:

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

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

我知道我的程序在哪里崩溃,但我知道为什么?它编译得很好。

我的代码在线崩溃

(*prevNode)->link = newNode; 

这是我看到这段代码的方式: 我将双指针 startPtr 传递给函数 add。然后我使用 malloc 创建了一个新节点。接下来我参考 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()

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

【问题讨论】:

  • 除了 head 未初始化之外,你的 add() 函数也有问题(它对 prevNode 的赋值不会改变调用者的变量)。
  • 是的,对不起,我早上搞砸了,我一定是不小心把它删了。我已经编辑了我的代码。我是编码新手,所以我不确定你的意思。我想因为我传递了一个指针,所以函数中所做的所有更改都将写入指针地址的内存位置。
  • 为什么重新打开?这不是“我正在尝试将数据存储到未初始化指针的地址”的重复项吗?我们不需要解释为什么每天 10 次没有意义。存在规范重复是有原因的。
  • startPtr = head 顺便说一句甚至不是有效的 C。好的,所以这段代码甚至无法编译。我们真的需要重新打开这个问题,对吧......
  • 此外,现在编辑的带有全局head 的版本更没有意义。这个全局变量被一个局部变量遮蔽。

标签: c list structure singly-linked-list


【解决方案1】:

这里有很多东西要解压......这些都是未初始化的,然后你给一个指针加上别名而不是指向一个地址,所以你真的没有指向一个指针的指针,你有两个相同的指针

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
}

【讨论】:

  • startPtr = head; 甚至不是有效的 C。这些不是兼容的指针类型。该行违反了简单赋值的约束。
【解决方案2】:

除了这个错别字

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;
}

【讨论】:

  • 第一个问题是代码首先无法编译,因为它不是有效的 C。startPtr = head; 这些不是兼容的指针类型。该行违反了简单赋值的约束。
  • @Lundin 我认为这只是一个错字,因为从它的帖子中可以看出存在分段错误。
【解决方案3】:
struct node *head;

从未初始化

startPtr = head;

已初始化为未初始化;超出这一点,您的整个程序都未定义。

【讨论】:

猜你喜欢
  • 2015-07-01
  • 1970-01-01
  • 2013-03-31
  • 2012-11-17
  • 2013-10-31
  • 2021-06-29
  • 2017-08-22
  • 2020-06-04
相关资源
最近更新 更多