链表中的指针操作

时间:2019-01-24 13:41:25

标签: c pointers linked-list

通常,我知道一个指针存储位于计算机内存中的另一个值的内存地址,例如:

int firstvalue= 5
int * p1;
p1 = &firstvalue;  // p1 = address of firstvalue

如果我们在链接列表中定义如下操作,会发生什么? *current=*list是否意味着current指向的值等于list指向的值?如果我们定义ecur=current是什么意思?

int function(struct list_t **list){
    struct list_t *ecur=NULL;
    struct list_t *current=*list;
    ecur=current;
}

更新*list=remove(*list, param1, param2)有什么作用?那为什么呢?

remove是一个返回list修改列表的函数。

更新2: 为什么我们需要定义一个指向指针的指针才能修改列表? *list是指向指针的指针吗?

5 个答案:

答案 0 :(得分:2)

变量list是指向结构list_t的指针。如果我们(仅作为示例)假设该结构放置在地址2000处,而未命名的指针位于地址1000处,它将看起来像这样:

enter image description here

然后,您将进行初始化,并添加了两个新变量。两者都是指向结构体list_t的指针。

struct list_t *ecur=NULL;
struct list_t *current=*list;

现在图片变成:

enter image description here

请注意,current与中间的“ some-pointer”具有相同的值,因为分配给*list的是current

然后您有任务:

ecur=current;

这意味着ecur获得与current相同的值并给出图片:

enter image description here

  

更新:*list=remove(*list, param1, param2)会做什么?

它更改图片中间的“指针”的值。例如,如果remove函数删除了链表中的第一个元素,则需要这样做。

答案 1 :(得分:1)

  

为什么我们需要定义一个指针以修改列表? * list是指向指针的指针吗?

请记住,C会按值传递所有函数参数-函数定义中的形式参数是内存中与函数调用中实际参数不同的对象。例如:

void swap( int a, int b )
{
  int tmp = a;
  a = b;
  b = tmp;
}

void foo( void )
{
  int x = 1;
  int y = 2;

  swap( x, y );
}

a是与x不同的内存对象,并且b是与y不同的内存对象,因此交换a和{{ 1}}对bx无效。为了交换yx的值,必须将 pointers 传递给它们:

y

表达式 void swap( int *a, int *b ) { int tmp = *a; *a = *b; *b = tmp; } void foo( void ) { int x = 1; int y = 2; swap( &x, &y ); } *a相同,因此写入x与写入*a相同。 x*b相同。

因此,要使函数写入参数,必须将 pointer 传递给该参数:

y

对于任何非数组类型void foo ( T *arg ) { *arg = new_value(); // writes a new value to the thing arg points to } void bar( void ) { T var; foo( &var ); // write a new value to var } ,这都是正确的。让我们用指针类型T替换T

P *

语义完全相同-所更改的只是类型。

如果某个函数有可能修改void foo( P **arg ) { *arg = new_value(); // write a new *pointer* value to the thing arg points to } void bar( void ) { P *var; foo( &var ); // write a new pointer value to var } 对象(例如,将其指向新的列表头),则必须将指针传递给该list *对象:

list *

答案 2 :(得分:0)

TYPE *p = ptype /*variable of type: TYPE * */;

不是分配。这是一个初始化,对于auto-matic(=堆栈上)p,可以重写为:

TYPE *p;
p = ptype;

(不是TYPE *p; *p=ptype; /*would be a type error*/

就您的示例而言:

struct list_t *current=*list;

设置current指向的位置(与*list指向的位置相同(*list也是一个指针,因为list是一个双向间接指针))初始化后无需对指向(*current的电流进行任何操作。

所有这些只是概念上的。您的函数没有任何外部可见的效果,因此优化的编译器应完全删除其主体。

答案 3 :(得分:0)

我和this post的想法相似。我想对您的功能进行一些重新安排,以便更轻松地了解发生了什么:

int function(struct list_t **list)
{
    struct list_t *current = *list;
    struct list_t *ecur    = current;
}

如果我们使用元素foo调用此函数,则基本上可以得到以下信息:

struct list_t foo      = { .data = "foo" };
struct list_t *bar     = &foo;
struct list_t **list   = &bar;
struct list_t *current = *list;
struct list_t *ecur    = current;

我们有五个声明和五个作业。为了提高可读性,我将所有内容都记下来而不声明:

foo     = { .data = "foo" };
bar     = &foo;
list    = &bar;
current = *list;
ecur    = current;

现在,让我们来看一下:

  1. foo是一个结构。它包含上面的数据字段。
  2. bar是指向struct的指针。它包含foo
  3. 的地址
  4. list是指向struct的指针。它包含bar
  5. 的地址
  6. current是指向struct的指针。它包含list内容的内容,它是foo的地址
  7. ecur是指向struct的指针。它与current相同,并且包含地址bar

最后,我们可以将整个示例简化为:

struct list_t foo   = { .data = "foo" };
struct list_t *ecur = &foo;

这是什么意思?

  • list:由于list是指向指针的指针,因此您可以通过取消引用bar来修改*list = ...使其指向完全不同的内容(current
  • ecur / bar:这也是(*ecur).data = "banana"最初的指向。通过取消引用,您可以更改数据字段本身(ecur->data或更好的class StreamCount: def __init__(self, input_values): self.input_values = input_values self.output = [] self.current_value = next(iter(input_values), None) # first element if there is any self.current_count = 0 def process_new(self, value): if value == self.current_value: self.current_count += 1 else: self.update_output() self.current_count = 1 self.current_value = value def process_all(self): for v in self.input_values: self.process_new(v) # handle last values suite self.update_output() return self.output def update_output(self): if self.current_count > 2: self.output.append(self.current_value) else: self.output += [self.current_value for _ in range(self.current_count)]

我希望我能澄清一些事情,并且不要让它变得更糟;)

答案 4 :(得分:0)

  

为什么我们需要定义一个指向该指针的指针才能修改   清单?

让我添加一个完整的程序,尽管简短,以更好地说明它。它定义一个简单的链表并在保持顺序的同时进行构建。是的,我知道简单地调用qsort()会更容易,但是我想展示一下如何添加一个间接级别(指向指针的指针)可以平滑地插入元素,而无需测试特殊情况。

// C pointer exercise: sort arguments
#include <stdio.h>
#include <strings.h>
#include <stdlib.h>

struct list
{
    char *arg;
    struct list *next;
};

int main(int argc, char *argv[])
{
    // pointer to base, running pointer and pointer to pointer
    struct list *base = NULL, *p, **pp;

    for (int i = 1; i < argc; ++i)
    {
        struct list *new_entry = malloc(sizeof(struct list));
        if (new_entry)
        {
            new_entry->arg = argv[i];

            // find where to insert new entry
            for (pp = &base; *pp; pp = &(*pp)->next)
                if (strcasecmp(new_entry->arg, (*pp)->arg) < 0)
                    break;

            // insertion in a simply linked list
            new_entry->next = *pp;
            *pp = new_entry;
        }
    }

    // display and cleanup
    for (p = base; p;)
    {
        struct list * tmp = p->next;
        puts(p->arg);
        free(p);
        p = tmp;
    }

    return 0;
}