【问题标题】:Pointer to a struct is not incrementing指向结构的指针不递增
【发布时间】:2018-09-15 17:12:11
【问题描述】:

我是 C 语言的新手,所以这段代码中可能存在我还不知道的逻辑错误。有一个卡片结构,它具有价值和花色作为字段。

我对这段代码的思考过程是:

  • 首先,创建一个指向卡片的指针。
  • 其次,在 for 循环中创建卡片并分配该卡片的字段。
  • 最后,指向创建的卡片并增加指针。

重复此过程,以便在内存地址中连续创建 52 个卡。 基本上我打算做的是为内存中的每 8 个字节创建一副卡片,但是循环内的 card_ptr++; 行并没有像我想象的那样工作。知道这里有什么问题吗?

我测试了注释部分,它按照我的意愿将指针增加了 8 个字节,但循环没有这样做。我还添加了打印语句以帮助您理解我的想法。

#include <stdio.h>

typedef enum {
  SPADES,
  HEARTS,
  DIAMONDS,
  CLUBS,
  NUM_SUITS
} suit_t;

struct card_tag {
  unsigned value;
  suit_t suit;
};
typedef struct card_tag card_t;

int main(){ 

    card_t *card_ptr;
    printf("Initial card pointer created. %d\n", card_ptr);
    for(int i =SPADES; i < NUM_SUITS; i++){
        for(int j = 1; j < 14; j++){
            card_t card;
            card.value = j;
            card.suit = i;
            printf("Card -> Value = %d Suit = %d, is created.\n", card.value, card.suit);
            card_ptr = &card;
            printf("%d points to the last card.\n", card_ptr);
            card_ptr++;
            printf("Pointer is incremented to %p\n\n", card_ptr);
        }   
    }

    /*card_t *card_ptr;
    printf("%d\n", card_ptr);
    card_ptr++;
    printf("%d\n", card_ptr);
    card_ptr++;
    printf("%d\n", card_ptr);
    */
}

【问题讨论】:

  • 最好在循环外创建一个cart_t 类型的数组,然后用指针访问它。
  • 使用一个数组,将指针分配给它,然后使用指针访问它。我就是这么说的。
  • printf("Initial card pointer created. %d\n", card_ptr); 调用 未定义的行为 有两个原因。 1. %d 不是正确的指针说明符,2. card_ptr 没有初始化,所以它有一个不确定的值
  • @gunessun 您的代码调用了未定义的行为,这不是编译时错误。这意味着您的代码可以为所欲为。
  • 您的代码没有在内存中创建 52 张卡片。它一次创建一张卡片。它会在循环迭代结束时销毁该卡,并在下一次迭代开始时创建一张新卡。为了创建 52 张卡片,您需要一个包含 52 个元素的数组。增加指针不会创建新卡片。

标签: c arrays pointers struct memory-address


【解决方案1】:

您的代码显然会导致未定义的行为。 如果你想用指针来做,请考虑下面的代码。

1:首先需要声明指向指针的指针。

card_t **card_ptr = malloc(sizeof(card_t*)*NUM_SUITS);

2:然后为每个指针分配内存。

card_ptr[i] = malloc(sizeof(card_t)*14);

3:增加指针如下。

card_ptr[i]++;

4:工作完成后使用free释放内存。

示例代码:

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

typedef enum {
  SPADES,
  HEARTS,
  DIAMONDS,
  CLUBS,
  NUM_SUITS
} suit_t;

struct card_tag {
  unsigned value;
  suit_t suit;
};
typedef struct card_tag card_t;

int main(){ 

    card_t **card_ptr = malloc(sizeof(card_t*)*NUM_SUITS);
    if (card_ptr == NULL) return 0;

    printf("Initial card pointer created. %d\n", card_ptr);

    for(int i =SPADES; i < NUM_SUITS; i++){

        card_ptr[i] = malloc(sizeof(card_t)*14);
        if (card_ptr[i] == NULL) return 0;

        card_t *tempPtr = card_ptr[i];

        for(int j = 1; j < 14; j++){

            tempPtr->value = j;
            tempPtr->suit = i;

            printf("Card -> Value = %d Suit = %d, is created.\n", tempPtr->value, tempPtr->suit);

            printf("%p points to the last card.\n", tempPtr);
            tempPtr++;
            printf("Pointer is incremented to %p\n\n", tempPtr);
        }   
    }

    /*card_t *card_ptr;
    printf("%d\n", card_ptr);
    card_ptr++;
    printf("%d\n", card_ptr);
    card_ptr++;
    printf("%d\n", card_ptr);
    */

     for(int i =SPADES; i < NUM_SUITS; i++){
        free(card_ptr[i]);
        card_ptr[i] = NULL;
     }
    free(card_ptr);
    card_ptr = NULL;

}

【讨论】:

  • 你需要stdlib.h
  • 我想问题是我只为一张空间卡分配内存,这就是为什么它没有增加,对吧?
  • 此版本使用动态分配的数组。一种或另一种方式需要一个数组。
  • @gunessun 是的,变量的范围也很短。
【解决方案2】:

这里更大的问题是card的声明范围。局部变量在堆栈上分配,当它们超出范围时,内存在某种意义上被“释放”(可以在其他地方使用,尽管可能不会重新初始化为零)。您的循环不断使用相同的内存区域,因为 card 超出范围,并在下一次循环迭代中重新创建。

正如其他人所指出的,您需要静态声明一个卡片数组,或者使用 malloc 确保它们在堆上停留。

以您的代码为起点,下面是一个示例:

示例(声明卡片数组并使用指针迭代)

card_t deck[52];

card_t *card_ptr = deck; /* Set pointer to the beginning of the array of cards */

printf("Initial card pointer created. %d\n", card_ptr);
for(int i =SPADES; i < NUM_SUITS; i++){
    for(int j = 1; j < 14; j++){
        card_ptr->value = j;
        card_ptr->suit = i;
        printf("Card -> Value = %d Suit = %d, is created.\n", card_ptr->value, card_ptr->suit);
        printf("%d points to the last card.\n", card_ptr);
        card_ptr++;
        printf("Pointer is incremented to %p\n\n", card_ptr);
    }   
}

【讨论】:

  • @Artem 当然,添加示例
  • 尊敬的 Lasidar,非常感谢您的全面解释。
  • @kiranBiradar 是的,我知道,并指出了很多。这纯粹是为了说明动态分配是如何发生的。他需要维护一个指针数组之类的东西,这些指针数组引用分配以使其正确。
  • 执行card_ptr++;时的行为也未定义
  • @kiranBiradar 我删除了第二个示例,因为虽然它说明了如何进行动态分配,但它只会导致更多的混乱。
猜你喜欢
  • 2013-02-23
  • 2021-03-04
  • 1970-01-01
  • 1970-01-01
  • 2016-03-21
  • 2012-03-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多