【问题标题】:Accessing data in a nested structure using pointers使用指针访问嵌套结构中的数据
【发布时间】:2021-05-21 17:39:34
【问题描述】:

我正在做一个作业,要求我编写一个包含嵌套结构的代码。问题其实很简单。只是为了获得矩形角的坐标。我一直在网上研究,但大多数例子都没有 typedef 结构。我的问题主要是不确定访问和存储数据的正确语法是什么。我的结构模板如下:

typedef struct
{
    double x;
    double y;
} Point; // Create a Point datatype;
typedef struct // nested structure
{
    Point topLeft; // topLeft is the variable name for "Point" structure with x&y property
    Point botRight; // botRight is the variable name for "Point" structure with x&y property
} Rectangle; // Create a Rectangle datatype with Point structure within
void getRect(Rectangle *r); // function prototype
int main()
{
Rectangle r; // initializing rectangle;
getRect(&r); // call function to get inputs using call by reference
}

void getRect(Rectangle *r)
{
    printf("Enter top left points:\n");
    scanf("%lf %lf", r->topLeft.x,r->topLeft.y); // Not sure if this is correct as my program can compile and run up till this point and crashes.
    printf("Enter bottom right points:\n");
    scanf("%lf %lf", r->botRight.x,r->botRight.y);
}

在这件事上寻求大家的善意指导!

【问题讨论】:

  • 节省时间,启用所有警告。

标签: c scanf pass-by-reference pass-by-value


【解决方案1】:

问题是scanf调用的参数应该是指针。例如

scanf("%lf %lf", &r->topLeft.x, &r->topLeft.y);

scanf("%lf %lf", &r->botRight.x, &r->botRight.y);

也就是说,您需要通过引用传递对象 x 和 y,函数 scanf 可以处理原始对象而不是其值的副本。

在 C 中,通过引用传递意味着通过指向对象的指针间接传递对象。在这种情况下,被调用的函数可以通过指针的解引用操作直接访问对象。

【讨论】:

  • 您好弗拉德,非常感谢您的友好意见。它解决了我的问题。对我来说是一个简单而惊人的学习点。对此,我真的非常感激。谢谢!
【解决方案2】:

scanf() 不分配内存,因此您必须始终传递函数可以为每个说明符放置数据的地址,例如%d%lf。因此,在您的情况下,您必须使用运算符的地址 & 传递每个 double 字段的地址

总是测试scanf()的返回。如果您无法获得其中一分,则没有理由继续读取数据

避免这种类型的评论:

    void getRect(Rectangle *r); // function prototype

很明显这是一个原型。您的代码中有一些这样的 cmets。更喜欢使用描述用途、参数、参数、算法的 cmets...

一个例子

下面的小程序以一些常用的方式声明你的结构,包括一个为每次调用返回Rectangle 的函数和一个打印数据的函数。通常用于测试。这只是一个例子。我不是说它是好还是最好或任何东西。

为了 SO 警察:我总是将指针指向 malloc(),因为,嗯,我这样做了。

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

typedef struct
{
    double x;
    double y;

}   Point;


typedef struct
{
    Point tL; // top left
    Point bR; // bottom right

}   Rectangle;

Rectangle*  rFactory();
int         showR(Rectangle*);

int         main(void)
{
    Point   A = { 2., 3. };

    Point   B = 
    {
        .y = 3.4,
        .x = 0.
    };

    Point*  pP = &A;
    printf( "Point is (%lf,%lf)\n", pP->x, pP->y ); // using pointer
    printf( "Point is (%lf,%lf)\n", A.x, A.y ); // using data directly

    Rectangle   R0 = { A,B };

    Rectangle   R1 =
    {
        {
            .x = 0.,
            .y = 2.
        },  // tL

        {  3.,4. } // bR
    };

    Rectangle   R2 = 
    {
        .bR = { 1.,2. },
        .tL = { -4.,-5 }
    };

    Rectangle*  pR = &R0;
    pR = &R1;
    pR = &R2; // :) just to get rid of the unused-var warnings 
    printf( "(via pointer) Rectangle is [(%lf,%lf), (%lf,%lf)]\n",
        pR->tL.x, pR->tL.y,
        pR->bR.x, pR->bR.y ); // using pointer
    printf( "(via data) Rectangle is [(%lf,%lf), (%lf,%lf)]\n",
        R2.tL.x, R2.tL.y,
        R2.bR.x, R2.bR.y ); // using data directly

    R2.bR.x = 0.;
    R2.bR.y = 0.;
    printf( "(Changed bR) Rectangle is [(%lf,%lf), (%lf,%lf)]\n",
        pR->tL.x, pR->tL.y,
        pR->bR.x, pR->bR.y ); // using pointer

    printf( "(Using function)\n\n");
    showR( &R2);

    // using a 'factory function gets a new one
    printf( "\n\n(Using factory function)\n\n");
    Rectangle*  other = rFactory();
    showR( other );
    free(other); // this one was allocated

    return 0;

}


Rectangle*  rFactory()
{
    Rectangle* one = (Rectangle*) malloc(sizeof(Rectangle));
    if ( one == NULL ) return NULL; // could not alloc
    int res = 0;

    printf("\
\tEnter points like '3., -2.3' separated by at least one space\
\n\tTop Left point: ");
    res = scanf("%lf %lf", &one->tL.x,&one->tL.y);
    if ( res != 2 )
    {
        free(one);
        return NULL;
    };  // if()

    printf("\
\n\tBottom Right point: ");
    res = scanf("%lf %lf", &one->bR.x,&one->bR.y);
    if ( res != 2 )
    {
        free(one);
        return NULL;
    };  // if()
    
    return one;
};


int     showR( Rectangle* pR)
{
    if ( pR == NULL ) return -1;
    printf( "\n\t[using showR()] Rectangle is [(%lf,%lf), (%lf,%lf)]\n",
        pR->tL.x, pR->tL.y,
        pR->bR.x, pR->bR.y ); // using pointer
    return 0;
}

输出

PS C:\src\bases> gcc -o tst -std=c17 -Wall sh.c
PS C:\src\bases> ./tst
Point is (2.000000,3.000000)
Point is (2.000000,3.000000)
(via pointer) Rectangle is [(-4.000000,-5.000000), (1.000000,2.000000)]
(via data) Rectangle is [(-4.000000,-5.000000), (1.000000,2.000000)]
(Changed bR) Rectangle is [(-4.000000,-5.000000), (0.000000,0.000000)]
(Using function)


        [using showR()] Rectangle is [(-4.000000,-5.000000), (0.000000,0.000000)]


(Using factory function)

        Enter points like '3., -2.3' separated by at least one space
        Top Left point: 1. 2.

        Bottom Right point: 3. 4.

        [using showR()] Rectangle is [(1.000000,2.000000), (3.000000,4.000000)]
PS C:\src\bases>

【讨论】:

  • 你好@arfneto。感谢您抽出宝贵时间进行如此深入的解释。对cmets的使用建议很好,以后一定会放置更多有意义的cmets!关于如何编写代码的一个非常有趣的替代视角。我永远不会这样写,因为我还是个初学者。将花时间分析和理解您编写的深入代码。先生,感激不尽。
  • 欢迎您
  • 请注意,上面的一半代码只是展示了如何声明、初始化和复制结构。它没有用,什么也没做。它只是一个例子。
  • Rectangle* other = rFactory();showR( other );free(other);。另一方面,是编程中非常常见且强大的构造factory functions,它返回指向新创建的东西的指针,在测试期间转储其内容的函数,以及释放该区域。当然,在实践中,连续 3 行并不常见
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-17
  • 2010-11-14
  • 1970-01-01
相关资源
最近更新 更多