指向链表中指针的指针 再次查看此代码,该代码插入列表的开头:这是输出另一个例子:在末尾插入另一用途:按升序插入删除列表示例程序的输出示例C程序

如何解决指向链表中指针的指针 再次查看此代码,该代码插入列表的开头:这是输出另一个例子:在末尾插入另一用途:按升序插入删除列表示例程序的输出示例C程序

有人可以解释一下为什么这段代码给我空列表吗?

typedef struct str_node{
int data;
struct str_node *next;
}node;


void begin(node *head);
void display_list(node *head);


int main(){

node *head;
int i;

head = NULL;

for(i=0;i<5;i++) {
    begin(head);
}
display_list(head);




return 0;
}

void begin(node *head){
node *new;
int value;
new = (node*) malloc(sizeof(node));
printf("Insert the element to add at the beginning of the list: ");
scanf("%d",&value);
new->data = value;
new->next = head;
head = new;
}

但是,如果我使用指向指针的指针更改了begin()函数,它会给我正确的列表吗?

void begin(node **head){
node *new;
int value;
new = (node*) malloc(sizeof(node));
printf("Insert the element to add at the beginning of the list: ");
scanf("%d",&value);
new->data = value;
new->next = *head;
*head = new;
}

您是否也可以解释一下为什么当我将主节点传递给函数开始时,我必须将其传递为“&head”?而不再是“头”

解决方法

在此代码段的第一个程序中

head = NULL;

for(i=0;i<5;i++) {
    begin(head);
}

指针head通过值传递给函数begin。即创建了main中声明的指针head的值的副本,并将其分配给与函数begin相同名称的参数

void begin(node *head);

因此,在函数内,参数head最初持有已更改的原始指针head的副本。其值已分配给该参数的原始指针head不会更改。

要更改main中声明的原始指针头,您必须像在第二个程序中一样,通过指向该指针头的指针间接地将其传递给函数。

因此该函数应声明为

void begin(node **head);

并且您必须通过指向它的指针间接传递指针头

begin( &head );

在这种情况下,取消引用传递的指针,该函数将直接访问main中声明的原始指针头并可以对其进行更改(而不是它的值的副本,因为它是在第一个函数定义中发生的)

new->next = *head;
*head = new;

为使内容更清楚,请考虑使用此简单的演示程序。

#include <stdio.h>

typedef int T;

void f( T t )
{
    t = 10;
}

int main(void) 
{
    T t = 0;
    
    printf( "Before calling f t is equal to %d\n",t );
    
    f( t );
    
    printf( "After  calling f t is equal to %d\n",t );

    return 0;
}

其输出为

Before calling f t is equal to 0
After  calling f t is equal to 0

当函数f处理传递的参数值的副本时,在main中声明的变量t的值未更改。

因此,您需要通过像这样的指针通过引用传递原始变量t

#include <stdio.h>

typedef int T;

void f( T *t )
{
    *t = 10;
}

int main(void) 
{
    T t = 0;
    
    printf( "Before calling f t is equal to %d\n",t );
    
    f( &t );
    
    printf( "After  calling f t is equal to %d\n",t );

    return 0;
}

现在程序输出为

Before calling f t is equal to 0
After  calling f t is equal to 10

在这些说明性程序中,名称T用作类型int的别名,而主要的对象t具有这种类型。

现在让我们假设名称T是int *类型的别名。

typedef int * T;

在这种情况下,例如在main中声明

T t = NULL;

表示变量t的指针类型为int *。那等于

int * t = NULL;

因此,要将其传递给必须更改原始变量t的函数,我们需要通过引用将其传递给

f( &t );

这意味着相应的函数应具有声明的参数类型,例如

void f( T *t );

但由于Tint *的别名,因此这意味着该函数具有类型为int **的参数。

void f( int * *t );
,

由于head是(实际上)是局部变量,因此更改*head不会对函数产生任何影响,而更改head会更改int指向的内容,因此也可以。

/ p>

如果您希望函数能够更改x变量中的值(例如x),则可以将其传递给指向int*的指针,该指针将具有键入x,您将使用&x获得指向x的指针。不论class ComplexRadar(): def __init__(self,fig,variables,ranges,n_ordinate_levels=6): angles = np.arange(0,360,360./len(variables)) axes = [fig.add_axes([0.1,0.1,0.9,0.9],polar=True,label = "axes{}".format(i)) for i in range(len(variables))] l,text = axes[0].set_thetagrids(angles,labels=variables) [txt.set_rotation(angle-90) for txt,angle #in zip(text,angles)] for ax in axes[1:]: ax.patch.set_visible(False) ax.grid("off") ax.xaxis.set_visible(False) for i,ax in enumerate(axes): grid = np.linspace(*ranges[i],#num=n_ordinate_levels) gridlabel = ["{}".format(round(x,2)) #for x in grid] if ranges[i][0] > ranges[i][1]: #grid = grid[::-1] # hack to invert grid # gridlabels aren't reversed gridlabel[0] = "" # clean up origin ax.set_rgrids(grid,labels=gridlabel,# angle=angles[i]) ax.spines["polar"].set_visible(False) ax.set_ylim(*ranges[i]) # variables for plotting self.angle = np.deg2rad(np.r_[angles,angles[0]]) self.ranges = ranges self.ax = axes[0] def plot(self,data,*args,**kw): sdata = _scale_data(data,self.ranges) self.ax.plot(self.angle,np.r_[sdata,sdata[0]],**kw) def fill(self,self.ranges) self.ax.fill(self.angle,**kw) # example data variables = ('Bench Press',"Vert Leap\xa0(in)",'Broad Jump\xa0(in)','Shuttle','3Cone','60Yd Shuttle','40\xa0Yard') data_rb = rb_mean_list data_wr = wr_mean_list data_qb = qb_mean_list data_lb = lb_mean_list data_t = t_mean_list data_de = de_mean_list data_dt = dt_mean_list data_g = g_mean_list data_te = te_mean_list data_fb = fb_mean_list ranges = [(0,50),(15,(0,150),(6,3),(10,6),(14,10),4)] # plotting fig,axs = plt.subplots(2,2) radar = ComplexRadar(fig,ranges) axs[0,0].radar.plot(data_rb) axs[0,0].radar.fill(data_rb,alpha=0.2) axs[0,0].set_title('rb') axs[0,1].radar.plot(data_wr) axs[0,1].radar.fill(data_wr,1].set_title('WR') plt.show() 是什么类型,都一样。

,

声明可能会引起一些困惑

    node        *head;

代替

    node*       head;

您要声明headhead是变量,它是一个指针。它不是节点。还要注意,节点不是链表:链表是节点的集合,可能还有其他的集合,以便获得有用的实现。最后在后面对此进行详细介绍。

事实是您在main()中声明为head,仅仅是node*。该节点本身甚至还不存在。您将begin()声明为

    void begin(node *head);

我想您会更清楚地看到它

    void begin(node*  parameter);

parameternode*

begin()内,您可以获得指针的副本,并且更改指针不会更改main()中的原始指针。 对于您而言,它将在main()中永远指向NULL

重要的是,指针就像任何变量一样:指针具有地址。和一个内容。当您按值传递值时,就像您所做的那样,begin()中的指针以NULL开头,即main()的值。但是它们之间的联系在通话中结束了:初始值。

当您将指针传递到begin()时,使用运算符'address of'并写入&head,事情发生了变化:您将使用运算符{{1}对其进行更改}表示您将更改其指向的地址,因此它将在'*'中进行更改。由于main()head的指针将被声明为node*

但是考虑使用以下方法更改链接列表的node**声明:

begin()

逻辑是插入节点可以更改列表的开头,因此您可以返回新地址,如

    node* begin(node* node);

是编写此代码的常用方法。另一种是使用node* _insert_begin(int value,node* pNode) { node* new = (node*)malloc(sizeof(node)); new->data = value; new->next = pNode; return new; }

我在这里描述的方式,任何可以更改列表头的操作都必须

  • 退回新头
  • 接收并更新指向头部的指针的指针

再次查看此代码,该代码插入列表的开头:

node**

返回node* _insert_begin(int value,node* pNode) { // insert 'value' at the start of the list node* new = (node*)malloc(sizeof(node)); (*new).data = value; new->next = pNode; return new; } ,即可更新new。您可以用head

来写
main()

注意行node* another = NULL; display_list(another); // inserts 5 to 0 at the beginning for (int i = 5; i >= 0; i -= 1) another = _insert_begin(i,another); printf("inserted 5..0 at the beginning\n"); display_list(another); ,您将看到another = _insert_begin(i,another);中的指针如何更新。

这是输出

main()

使用empty list inserted 5..0 at the beginning 0 1 2 3 4 5 list has 6 elements 的此实现,每行打印5个值:

display_list()

另一个例子:在末尾插入

请注意,如果列表为空,则在末尾插入也可以更改头,所以我们仍然需要返回头地址

int display_list(node* p)
{
    if (p == NULL)
    {
        printf("empty list\n");
        return 0;
    };
    int count = 0;
    // not empty
    do
    {
        printf("%8d ",p->data);
        count++;
        if (count % 5 == 0) printf("\n");
        p = p->next;
    } while (p != NULL);
    if (count % 5 != 0) printf("\n");
    printf("list has %d elements\n",count);
    return count;
};

另一用途:按升序插入

当然,按升序插入也可以改变头,就像

node* _insert_end(int value,node* pNode)
{   // insert value at the end of the list
    node* new = (node*)malloc(sizeof(node));
    new->data = value;
    new->next = NULL;
    if (pNode == NULL) return new;
    node* p = pNode;
    while (p->next != NULL) p = p->next;
    p->next = new;
    return pNode;
}

删除列表

删除列表还应返回node* _insert_ordered(int value,node* pNode) { // insert value at ascending order in the list node* new = (node*)malloc(sizeof(node)); new->data = value; new->next = NULL; if (pNode == NULL) return new; node* p = pNode; node* prev = NULL; // previous node: list if forward only while (p->next != NULL) { if (new->data < p->data) { // insert before first greater than value if (prev == NULL) { // new head new->next = p; return new; }; // if() prev->next = new; new->next = p; return pNode; // no change in head }; prev = p; p = p->next; // updates pointers }; // while() // we are at the end: new will be the last? if (new->data < p->data) { if (prev == NULL) pNode = new; else prev->next = new; new->next = p; } else { p->next = new; }; return pNode; } // _insert_ordered() ,以使头部指针无效。这是平常的。当您习惯了它的机制时,这可以确保不会在周围留下无效的指针。

请注意,这种逻辑是协作的:您必须在每次可以更改磁头的调用时都将磁头指针分配回去

node*

正在运行的程序

示例程序的输出

node* delete_list(node* H)
{
    if (H == NULL) return NULL;
    if (H->next == NULL)
    {   // single node
        free(H);
        return NULL; 
    };
    // more than one node
    do
    {   node* p = H->next;
        free(H);
        H = p;
    } while (H != NULL);
    return NULL;
};

示例C程序

empty list
inserted 5..0 at the beginning
       0        1        2        3        4
       5
list has 6 elements
inserted 6 to 10 at the end
       0        1        2        3        4
       5        6        7        8        9
      10
list has 11 elements
inserted 0 to 10,ordered
       0        0        1        1        2
       2        3        3        4        4
       5        5        6        6        7
       7        8        8        9        9
      10       10
list has 22 elements
inserted -1 to -10,ordered
     -10       -9       -8       -7       -6
      -5       -4       -3       -2       -1
       0        0        1        1        2
       2        3        3        4        4
       5        5        6        6        7
       7        8        8        9        9
      10       10
list has 32 elements
inserted 11 to 20,ordered
     -10       -9       -8       -7       -6
      -5       -4       -3       -2       -1
       0        0        1        1        2
       2        3        3        4        4
       5        5        6        6        7
       7        8        8        9        9
      10       10       11       12       13
      14       15       16       17       18
      19       20
list has 42 elements
about to delete list
empty list

一种可能更有用的链表结构

请考虑以下内容

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

typedef struct str_node
{
    int             data;
    struct str_node* next;
}   node;

void    begin(node* pNode);
node*   delete_list(node*);
int     display_list(node*);
node*   _insert_begin(int,node*);
node*   _insert_end(int,node*);
node*   _insert_ordered(int,node*);

int main()
{
    node* another = NULL;
    display_list(another);

    // insert 5 to 0 at the beginning
    for (int i = 5; i >= 0; i -= 1)
        another = _insert_begin(i,another);
    printf("inserted 5..0 at the beginning\n");
    display_list(another);

    // insert 6 to 10 at the end
    for (int i = 6; i <= 10; i += 1)
        another = _insert_end(i,another);
    printf("inserted 6 to 10 at the end\n");
    display_list(another);

    // insert 0 to 10 ordered
    for (int i = 0; i <=10; i += 1)
        another = _insert_ordered(i,another);
    printf("inserted 0 to 10,ordered\n");
    display_list(another);

    // insert -1 to -10 ordered
    for (int i = -1; i >= -10; i -= 1)
        another = _insert_ordered(i,another);
    printf("inserted -1 to -10,ordered\n");
    display_list(another);

    // insert 11 to 20 ordered
    for (int i = 11; i <= 20; i += 1)
        another = _insert_ordered(i,another);
    printf("inserted 11 to 20,ordered\n");
    display_list(another);

    printf("about to delete list\n");
    another = delete_list(another);
    display_list(another);
    return 0;
}

node* delete_list(node* H)
{
    if (H == NULL) return NULL;
    if (H->next == NULL)
    {   // single node
        free(H);
        return NULL; 
    };
    // more than one node
    do
    {   node* p = H->next;
        free(H);
        H = p;
    } while (H != NULL);
    return NULL;
};

node* _insert_begin(int value,node* pNode)
{   // insert 'value' at the start of the list
    node* new = (node*)malloc(sizeof(node));
    (*new).data = value;
    new->next = pNode;
    return new;
}

node* _insert_end(int value,node* pNode)
{   // insert value at the end of the list
    node* new = (node*)malloc(sizeof(node));
    new->data = value;
    new->next = NULL;
    if (pNode == NULL) return new;
    node* p = pNode;
    while (p->next != NULL) p = p->next;
    p->next = new;
    return pNode;
}

node* _insert_ordered(int value,node* pNode)
{   // insert value at ascending order in the list
    node* new = (node*)malloc(sizeof(node));
    new->data = value;
    new->next = NULL;
    if (pNode == NULL) return new;

    node* p = pNode;
    node* prev = NULL; // previous node: list if forward only
    while (p->next != NULL)
    {
        if (new->data < p->data)
        {
            // insert before first greater than value
            if (prev == NULL)
            {
                // new head
                new->next = p;
                return new;
            };  // if()
            prev->next = new;
            new->next = p;
            return pNode; // no change in head
        };
        prev = p; p = p->next; // updates pointers
    };  // while()
    // we are at the end: new will be the last?
    if (new->data < p->data)
    {
        if (prev == NULL)
            pNode = new;
        else
            prev->next = new;
        new->next = p;
    }
    else
    {
        p->next = new;
    };
    return pNode;
}   // _insert_ordered()

int display_list(node* p)
{
    if (p == NULL)
    {
        printf("empty list\n");
        return 0;
    };
    int count = 0;
    // not empty
    do
    {
        printf("%8d ",count);
    return count;
};

这样,将链表定义为节点的容器。

  • 它甚至还有一个可选的struct no { void* item; struct no* next; struct no* prev; }; // no typedef struct no Node; typedef struct { // example,more flexible char* name; unsigned size; unsigned capacity; Node* head; Node* tail; } Linked_list;
  • name始终可用并且是最新的
  • 大小限制可以实现为size
  • 在末尾插入并不需要您跟随所有其他节点,因为列表封装了指向头尾的指针
  • 一个节点具有指向下一个和上一个节点的指针,因此可以更轻松地迭代某些数据,例如播放列表或类似的集合。
  • 一个程序可以有任意数量的列表,因为每个列表都封装了所有这些元数据。
  • 列表可以包含任何内容,因为数据是指向void capacity
  • 的指针
  • empty()或size()之类的函数可以轻松实现
  • 所有函数都使用指向列表的指针
void*
,

关于:

void begin(node *head){

更改head仅更改调用堆栈的“ head”,所需的是更改调用者函数中“ head”指向的位置。为此,呼叫者必须传递“ head”的地址。 “头”本身就是一个指针这一事实无助于明确说明需要做的事情,

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-