คุณสร้างอาร์เรย์ของโครงสร้างใน C ได้อย่างไร?


101

ฉันกำลังพยายามสร้างอาร์เรย์ของโครงสร้างโดยแต่ละโครงสร้างแทนเทห์ฟากฟ้า

ฉันไม่มีประสบการณ์กับโครงสร้างมากขนาดนั้นซึ่งเป็นเหตุผลว่าทำไมฉันจึงตัดสินใจลองใช้มันแทนอาร์เรย์ทั้งหมด อย่างไรก็ตามฉันยังคงพบข้อผิดพลาดต่างๆมากมาย ฉันได้พยายามใช้เทคนิคที่ฉันเคยเห็นในเธรดต่างๆและบน StackOverflow (เช่นArray of structs ใน CและC - เริ่มต้นอาร์เรย์ของโครงสร้าง ) แต่ไม่สามารถใช้ได้ทั้งหมด

ข้อมูลเพิ่มเติมสำหรับผู้ที่อ่านมาจนถึงตอนนี้: ฉันไม่ต้องการให้สิ่งนี้เป็นแบบไดนามิกฉันรู้ / กำหนดขนาดของทุกอย่างล่วงหน้า ฉันต้องการให้สิ่งนี้เป็นอาร์เรย์ส่วนกลางเนื่องจากฉันเข้าถึงสิ่งนี้ด้วยวิธีการต่างๆซึ่งได้กำหนดอาร์กิวเมนต์ (เช่นเมธอด GLUT)

นี่คือวิธีที่ฉันกำหนดโครงสร้างในส่วนหัวของฉัน:

struct body
{
    double p[3];//position
    double v[3];//velocity
    double a[3];//acceleration
    double radius;
    double mass;
};

ฉันมีรายการตัวแปรส่วนกลางอื่น ๆ ที่ฉันกำหนดก่อนที่ฉันจะกำหนดภายในของโครงสร้างและหนึ่งในนั้นคืออาร์เรย์ของโครงสร้างนี้ (โดยทั่วไปถ้าฉันไม่ชัดเจนเกินไปในการพูดที่มีหมอกของฉันบรรทัดด้านล่าง อยู่เหนือสิ่งต่างๆด้านบน):

struct body bodies[n];

เพียงเพื่อให้คุณรู้ว่าnเป็นสิ่งที่ฉันได้ถูกต้องตามกฎหมายที่กำหนดไว้ (เช่น#define n 1)

ฉันใช้อาร์เรย์นี้ในหลายวิธี แต่วิธีที่ง่ายที่สุดและใช้พื้นที่น้อยที่สุดคือรูปแบบที่เรียบง่ายของ main ของฉัน ที่นี่ฉันเริ่มต้นตัวแปรทั้งหมดในแต่ละโครงสร้างเพียงเพื่อตั้งค่าตัวแปรให้แน่นอนก่อนที่ฉันจะแก้ไขในบางวิธี:

  int a, b;
 for(a = 0; a < n; a++)
 {
        for(b = 0; b < 3; b++)
        {
            bodies[a].p[b] = 0;
            bodies[a].v[b] = 0;
            bodies[a].a[b] = 0;
        }
        bodies[a].mass = 0;
        bodies[a].radius = 1.0;
 }

ข้อผิดพลาดปัจจุบันที่ฉันเผชิญคือnbody.c:32:13: error: array type has incomplete element typeโดยที่บรรทัด 32 คือจุดที่ฉันสร้างอาร์เรย์ของโครงสร้าง

การชี้แจงครั้งสุดท้ายโดยส่วนหัวฉันหมายถึงช่องว่างด้านบนint main(void)แต่อยู่ใน*.cไฟล์ เดียวกัน


มันใช้ได้ดีสำหรับฉัน ประกาศstruct body bodies[n];ก่อนstruct body {}ประกาศไม่ใช่เหรอ
แจ็ค

โปรดทราบว่าการใช้อาร์เรย์ที่มีความยาวผันแปรมักทำให้เกิดบั๊กลึกลับหรือล่มได้เมื่อขนาดของอาร์เรย์เกินขนาดสแต็กของโปรแกรมในระบบของคุณ (ซึ่งไม่สามารถควบคุมได้โดยสิ้นเชิงในฐานะโปรแกรมเมอร์) จะดีกว่าถ้าใช้ malloc () สำหรับสิ่งนี้
เอเดรีย

@adrian ฉันคิดว่ามันเป็น#defineค่า d มันไม่ใช่ตัวแปร มันจะเหมือนกับstruct body bodies[1]หรือมูลค่าของnมันคืออะไร
โปรแกรม Redwolf

@RedwolfPrograms อาขอโทษฉันไม่ได้พิจารณาเรื่องนั้น สำหรับเร็กคอร์ดถ้าnเป็นค่าคงที่ซึ่งสามารถกำหนดได้ในเวลาคอมไพล์คุณอาจปลอดภัย
เอเดรีย

คำตอบ:


107
#include<stdio.h>
#define n 3
struct body
{
    double p[3];//position
    double v[3];//velocity
    double a[3];//acceleration
    double radius;
    double mass;
};

struct body bodies[n];

int main()
{
    int a, b;
     for(a = 0; a < n; a++)
     {
            for(b = 0; b < 3; b++)
            {
                bodies[a].p[b] = 0;
                bodies[a].v[b] = 0;
                bodies[a].a[b] = 0;
            }
            bodies[a].mass = 0;
            bodies[a].radius = 1.0;
     }

    return 0;
}

ใช้งานได้ดี คำถามของคุณยังไม่ชัดเจนนักดังนั้นให้จับคู่รูปแบบของซอร์สโค้ดของคุณกับด้านบน


นอกจากนี้ฉันมีคำถามเกี่ยวกับตำแหน่งระหว่างการประกาศประเภทของโครงสร้างจากนั้นจึงสร้างอินสแตนซ์ของมันขึ้นมา - ฉันมีโครงสร้างที่แตกต่างกันซึ่งฉันกำหนดเนื้อหาด้านล่างที่ฉันสร้างอินสแตนซ์ของมันเป็นครั้งแรก (เพียงอันเดียว คราวนี้ไม่ใช่อาร์เรย์) เหตุใดจึงไม่ทำให้เกิดข้อผิดพลาดจำนวนมาก มันใช้งานได้ดีซึ่งทำให้ฉันคิดว่าความพยายามในการสร้างอาร์เรย์ของฉันน่าจะได้ผลเช่นกัน แต่คราวนี้ไม่ได้ผล นอกจากนี้ขอขอบคุณสำหรับคำตอบของคุณมันได้ผล
Amndeep7

1
หวัดดี .... 59 ไลค์? ฉันไม่เห็นอาร์เรย์ของโครงสร้างฉันเห็นเฉพาะอาร์เรย์ของตัวแปรจากขีด ...

12

ฉันคิดว่าคุณก็เขียนแบบนั้นได้เช่นกัน ฉันยังเป็นนักเรียนดังนั้นฉันจึงเข้าใจการต่อสู้ของคุณ ตอบช้าไปหน่อย แต่ก็โอเค

#include<stdio.h>
#define n 3

struct {
    double p[3];//position
    double v[3];//velocity
    double a[3];//acceleration
    double radius;
    double mass;
}bodies[n];

12

ดังนั้นเพื่อรวบรวมทั้งหมดเข้าด้วยกันโดยใช้malloc():

int main(int argc, char** argv) {
    typedef struct{
        char* firstName;
        char* lastName;
        int day;
        int month;
        int year;

    }STUDENT;

    int numStudents=3;
    int x;
    STUDENT* students = malloc(numStudents * sizeof *students);
    for (x = 0; x < numStudents; x++){
        students[x].firstName=(char*)malloc(sizeof(char*));
        scanf("%s",students[x].firstName);
        students[x].lastName=(char*)malloc(sizeof(char*));
        scanf("%s",students[x].lastName);
        scanf("%d",&students[x].day);
        scanf("%d",&students[x].month);
        scanf("%d",&students[x].year);
    }

    for (x = 0; x < numStudents; x++)
        printf("first name: %s, surname: %s, day: %d, month: %d, year: %d\n",students[x].firstName,students[x].lastName,students[x].day,students[x].month,students[x].year);

    return (EXIT_SUCCESS);
}

8
สาย malloc ของคุณควรมี numStudents * sizeof (STUDENT) หรือไม่
ทอดด์

@Todd จะดีกว่าไม่. sizeof *studentsเป็นสิ่งเดียวกันและจะไม่ผิดถ้า STUDENT เคยเปลี่ยนแปลง
trentcl

@trentcl เขาได้จัดสรรหน่วยความจำสำหรับจำนวนพอยน์เตอร์จำนวน {numStudents} ไม่ใช่โครงสร้าง แต่เป็นตัวชี้ ขนาดของตัวชี้มักจะเป็น 4 ไบต์ในขณะที่ขนาดของโครงสร้างคือ 20 ไบต์ 20 ไบต์เป็นจำนวนหารด้วย 4 ได้ดังนั้นจึงไม่จำเป็นต้องมีช่องว่างภายในและโครงสร้างจะถูกเก็บไว้ในทุกๆ 20 ไบต์จากที่อยู่เริ่มต้น ใช้งานได้เพราะคุณจัดสรรหน่วยความจำสำหรับกรณีเฉพาะเท่านั้น มิฉะนั้น mallocs อื่น ๆ อาจเขียนทับหน่วยความจำของโครงสร้างของคุณเนื่องจากไม่ได้รับการจัดสรรและคุณมีหน่วยความจำของนักเรียนมากเกินไป
John Smith

3
@JohnSmith คุณเข้าใจผิด; อ่านอีกครั้ง sizeof *studentsคือขนาดของสิ่งที่ชี้ไปที่คือไม่sizeof(STUDENT) sizeof(STUDENT*)คุณกำลังทำผิดพลาดที่ptr = malloc(num * sizeof *ptr)สำนวนควรจะป้องกัน ตรวจสอบได้ที่นี่ (โปรดทราบว่าเซิร์ฟเวอร์เช่นเดียวกับพีซีที่ทันสมัยที่สุดมีตัวชี้ 8 ไบต์ดังนั้นขนาดจึงเป็น 8 และ 32 แทนที่จะเป็น 4 และ 20)
trentcl

@trentcl ขอบคุณสำหรับคำอธิบาย ฉันสับสนกับไวยากรณ์ของตัวชี้การอ้างอิงในการเริ่มต้นของมันเอง ฉันจะบอกว่ามันสับสนเล็กน้อย แต่เป็นโซลูชันที่กะทัดรัดกว่า
John Smith

8

ย้าย

struct body bodies[n];

หลังจากนั้น

struct body
{
    double p[3];//position
    double v[3];//velocity
    double a[3];//acceleration
    double radius;
    double mass;
};

ส่วนที่เหลือทั้งหมดดูดี


6

อีกวิธีหนึ่งในการเตรียมใช้งานอาร์เรย์ของโครงสร้างคือการเตรียมข้อมูลเบื้องต้นให้กับสมาชิกอาร์เรย์อย่างชัดเจน วิธีนี้มีประโยชน์และเรียบง่ายหากมีสมาชิกโครงสร้างและอาร์เรย์ไม่มากเกินไป

ใช้ตัวtypedefระบุเพื่อหลีกเลี่ยงการใช้structคำสั่งซ้ำทุกครั้งที่คุณประกาศตัวแปรโครงสร้าง:

typedef struct
{
    double p[3];//position
    double v[3];//velocity
    double a[3];//acceleration
    double radius;
    double mass;
}Body;

จากนั้นประกาศโครงสร้างอาร์เรย์ของคุณ การเริ่มต้นของแต่ละองค์ประกอบจะไปพร้อมกับการประกาศ:

Body bodies[n] = {{{0,0,0}, {0,0,0}, {0,0,0}, 0, 1.0}, 
                  {{0,0,0}, {0,0,0}, {0,0,0}, 0, 1.0}, 
                  {{0,0,0}, {0,0,0}, {0,0,0}, 0, 1.0}};

หากต้องการทำซ้ำนี่เป็นวิธีแก้ปัญหาที่ค่อนข้างง่ายและตรงไปตรงมาหากคุณไม่มีองค์ประกอบอาร์เรย์มากเกินไปและสมาชิกโครงสร้างขนาดใหญ่และถ้าคุณตามที่คุณระบุไว้ไม่สนใจแนวทางที่มีพลวัตมากขึ้น วิธีนี้ยังมีประโยชน์หากสมาชิกของโครงสร้างเริ่มต้นด้วยตัวแปร enum ที่มีชื่อ (ไม่ใช่แค่ตัวเลขเหมือนตัวอย่างด้านบน) ซึ่งจะช่วยให้ผู้อ่านโค้ดเห็นภาพรวมของวัตถุประสงค์และหน้าที่ของโครงสร้างและสมาชิกได้ดีขึ้น แอปพลิเคชัน


1
รักสิ่งนี้! คำตอบที่ดีและเรียบง่าย👍
Ethan

1

ข้อผิดพลาดนั้นหมายความว่าคอมไพลเลอร์ไม่สามารถค้นหาคำจำกัดความของประเภทของโครงสร้างของคุณก่อนที่จะประกาศอาร์เรย์ของโครงสร้างเนื่องจากคุณกำลังบอกว่าคุณมีคำจำกัดความของโครงสร้างในไฟล์ส่วนหัวและข้อผิดพลาดnbody.cก็เกิดขึ้น คุณควรตรวจสอบว่าคุณรวมไฟล์ส่วนหัวอย่างถูกต้องหรือไม่ ตรวจสอบของคุณ#includeและตรวจสอบให้แน่ใจว่าได้กำหนดนิยามของโครงสร้างก่อนที่จะประกาศตัวแปรประเภทนั้น ๆ


ฉันสงสัยว่า OP หมายถึงส่วนหัวเป็นไฟล์ส่วนหัวตามที่เขาเขียนว่า "บรรทัดด้านล่างอยู่เหนือสิ่งที่อยู่ด้านบน" ก่อนการประกาศโครงสร้างอาร์เรย์ซึ่งอยู่ในไฟล์ nbody.c ของเขา รอให้เขาตื่นขึ้นมาและเคลียร์ข้อสงสัย
nims

@nims ถูกต้องโดยส่วนหัวฉันหมายถึงพื้นที่ด้านบนmainข้อความ
Amndeep7

1

วิธีแก้ไขโดยใช้พอยน์เตอร์:

#include<stdio.h>
#include<stdlib.h>
#define n 3
struct body
{
    double p[3];//position
    double v[3];//velocity
    double a[3];//acceleration
    double radius;
    double *mass;
};


int main()
{
    struct body *bodies = (struct body*)malloc(n*sizeof(struct body));
    int a, b;
     for(a = 0; a < n; a++)
     {
            for(b = 0; b < 3; b++)
            {
                bodies[a].p[b] = 0;
                bodies[a].v[b] = 0;
                bodies[a].a[b] = 0;
            }
            bodies[a].mass = 0;
            bodies[a].radius = 1.0;
     }

    return 0;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.