【问题标题】:C Pointer Arithmetic, moving around in memoryC指针算术,在内存中移动
【发布时间】:2021-08-23 01:57:58
【问题描述】:

在下面的代码中,为什么current->next = (char*) current + sizeof(Node); 可以工作,而current->next = current + sizeof(Node); 却不行?

我不知道为什么当它们在我的系统上的字节大小相同时,我必须将 'current' 转换为 char* 而不是将其保留为 Node*。

// on my system
// sizeof(char*) is 4 bytes
// sizeof(Node*) is 4 bytes
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {

    typedef struct Node {
        int data;
        struct Node* next;
        struct Node* prev;
    } Node;

    void* heap = malloc(25 * sizeof(Node));

    Node* head = (Node*) heap;
    head->prev = NULL;
    Node* tail = (char*) head + (24 * sizeof(Node));
    tail->next = NULL;
    Node* current = head;

    int i = 0;
    while (current != NULL) {
        current->data = i;
        if (current != tail)
            current->next = (char*) current + sizeof(Node);
        if (current->next != NULL)
            current->next->prev = current;
        current = current->next;
        i++;
    }

    printf("\n");

    current = head;
    while (current != NULL) {
        printf("%d->", current->data);
        current = current->next;
    }

    return(0);
}

【问题讨论】:

  • @DavidC.Rankin 由于指针运算不应该是current-&gt;next = current + 1;吗?
  • 是的,例如Node* tail = head + 24;current-&gt;next = current + 1;
  • (编辑)删除所有演员表,例如Node* head = heap;current-&gt;next = current + 1; 在 C 中,void 指针可以分配给任何类型,也可以分配给任何类型,而无需强制转换。分配给类型 Node* 时仅转换算术表达式的一部分,例如current-&gt;next = (char*) current + sizeof(Node); 导致 "initialization from incompatible pointer type"

标签: c pointers


【解决方案1】:

在 C 中,指针运算以指向类型为单位进行操作。如果指针的类型为 char *,则向其添加 1 或 2 或 3 会将其调整为指向 char,即 char 数组中稍后的 1 或 2 或 3 个元素。如果指针的类型为 Node *,则向其添加 1 或 2 或 3 会将其调整为指向 Node,即 Node 数组中稍后的 1 或 2 或 3 个元素。

如果current 指向某个Node X,那么current + 1 将指向X 之后的Node。相反,如果sizeof (Node) 是12 个字节,那么current + sizeof(Node) 指向Node 即比 X 晚 12 个数组元素,所以 12•12 = 比 X 晚 144 个字节。

(char *) current + sizeof (Node) 中,current 被转换为char *。然后在这个char *上的指针运算以char为单位进行运算,所以(char *) current + sizeof (Node)指向X后12个字节,也就是一个Node的距离,所以它指向X后的Node

sizeof (char *)sizeof (Node *) 在您的 C 实现中是相同的这一事实无关紧要。这些是指针的大小,而不是指向的事物的大小。 char *Node * 上的指针运算以 sizeof (char)sizeof (Node) 为单位运行。

(顺便说一句,我写sizeof (char *)而不是sizeof(char *)来表达sizeof不是一个函数,括号不标记参数列表。相反,sizeof是一个运算符,这里的括号在 C 语法中用于区分类型。)

【讨论】:

  • 这是一个很好的解释,但第 2 段中的短语“12 个元素晚于 X”可能会造成混淆,因为不清楚您在这里使用“元素”来指代节点. (或者,更确切地说,它清楚的,但仅限于已经理解您要说的内容的人。)也许在示例中提及current + sizeof(Node) == current + 12 == (char *)current + 144 会很有用。或者也许只是完全摆脱特定的例子。
【解决方案2】:

如果您尝试创建双链表,那么为什么要创建节点数组?您创建了 25 个节点的数组,这不是链表。

Node* tail = (char*) head + (24 * sizeof(Node));

为什么是指向 char (char*) 的指针?你告诉编译器它指向字符,这是故意的。 无论如何,要指向最后一个节点,您必须在它们之间添加字节数,即 (24*sizeof(Node))。它是字符指针的类型,但是你分配给一个类型是指向节点的指针的变量,所以它会自动转换为指向节点的指针。

但是如果你没有告诉编译器,它会根据指针指向的数据大小来调整指针的加法,在这种情况下它是 Node.js。由于 head 是指向节点的指针,因此加一将添加 sizeof(Node)。所以简单地使用,

Node* tail = head+24;

由于您创建了一个节点数组,因此您不需要创建指向下一个节点的链接。但是为了练习, current 已经是指向节点的指针。 如果您将其转换为占用 1 个字节的 char,那么您必须在两个节点之间添加字节数,在这种情况下,这又是相同的 sizeof(Node)。

current->next = (char*) current + sizeof(Node);

但是如果你不强制转换它,它已经是一个指向 Node 的指针,向它添加一个将等于添加 sizeof(Node)。

current->next = current + 1;

【讨论】:

  • 这没有回答所提出的问题。
  • @EricPostpischil 首先进入单字节级别,而不是故意添加字节数。我会解决的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-27
  • 2010-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多