C'de bir yapı dizisi nasıl yapılır?


101

Her yapının bir gök cismi temsil ettiği bir dizi yapı oluşturmaya çalışıyorum.

Yapılar konusunda pek tecrübem yok, bu yüzden bir sürü dizi yerine onları kullanmaya karar verdim. Ancak, birçok farklı hatayla karşılaşmaya devam ediyorum. Çeşitli iş parçacıkları ve StackOverflow'da gördüğüm teknikleri ( C ve C'deki yapı dizisi gibi - yapı dizisini başlat ) uygulamaya çalıştım , ancak bunların hepsi uygulanabilir değildi.

Şimdiye kadar okumuş olanlar için daha fazla bilgi: Dinamik olmak için bunların hiçbirine ihtiyacım yok, her şeyin boyutunu önceden biliyorum / tanımlıyorum. Ayrıca, buna argümanları tanımlayan birkaç farklı yöntemle (yani GLUT yöntemleri) eriştiğim için bunun global bir dizi olmasına da ihtiyacım var.

Başlığımdaki yapıyı bu şekilde tanımlıyorum:

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

Yapının iç kısmını tanımlamadan önce tanımladığım diğer küresel değişkenlerin bir listesi var ve bunlardan biri bu yapının dizisi (temelde, sisli konuşmamda çok net değilsem, aşağıdaki satır yukarıdaki şeylerin üzerindedir):

struct body bodies[n];

Bildiğiniz gibi, nmeşru olarak tanımladığım bir şey (yani #define n 1).

Bu diziyi birkaç farklı yöntemde kullanıyorum, ancak en kolay ve en az yer kaplayan, ana dizimin basitleştirilmiş bir şeklidir. Burada, bir şekilde değiştirmeden önce değişkenleri belirli bir şekilde ayarlamak için, yapıların her birindeki tüm değişkenleri başlatıyorum:

  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;
 }

Şu an karşılaştığım hata, nbody.c:32:13: error: array type has incomplete element type32. satırın yapı dizisini yaptığım yer.

Son bir açıklama, başlık ile yukarıdaki alanı kastediyorum, int main(void)ancak aynı *.cdosyada.


Benim için iyi çalışıyor. Beyannameden struct body bodies[n];önce struct body {}beyan etmiyor musunuz ?
Jack

Değişken uzunluklu diziler kullanmanın, dizinin boyutu programın sisteminizdeki yığın boyutunu aştığında (bir programcı olarak tamamen sizin kontrolünüz dışında olan) genellikle gizemli hatalara veya çökmelere neden olabileceğini unutmayın. Bu tür şeyler için malloc () kullanmak daha iyidir.
adrian

@adrian Bence bir #defined değeri olduğu için değişken değil. Aynı struct body bodies[1]ya da değeri ne olursa olsun aynı olacaktır n.
Redwolf Programları

@RedwolfPrograms ah üzgünüm, bunu dikkate almadım. Kayıt için, nderleme zamanında belirlenebilen bir sabitse, muhtemelen güvendesiniz.
adrian

Yanıtlar:


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;
}

bu iyi çalışıyor. Bu arada sorunuz çok net değildi, bu nedenle kaynak kodunuzun düzenini yukarıdakilerle eşleştirin.


Ayrıca, yapı türünün bildirimi arasındaki yerleşim hakkında bir sorum var ve daha sonra bunun bir örneğini oluşturuyorum - Farklı bir yapıya sahibim, aşağıdaki içeriğini tanımladığım, ilk önce bir örneğini oluşturduğum yer (sadece bir bu sefer, bir dizi değil), öyleyse bu neden büyük bir hata dizisi oluşturmadı? Gayet iyi çalıştı, bu da beni bir dizi oluşturma girişimimin de işe yaraması gerektiğini düşünmeye sevk etti, ancak bu sefer işe yaramadı. Ayrıca cevabınız için teşekkür ederim, işe yaradı.
Amndeep7

1
Merhaba, .... 59 beğeni? Struct dizilerini görmedim, sadece vurdu ...

12

Bence sen de öyle yazabilirsin. Ben de öğrenciyim, bu yüzden mücadelenizi anlıyorum. Biraz geç cevap ama tamam.

#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

Yani hepsini kullanarak bir araya getirmek için 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 hattınızda numStudents * sizeof (STUDENT) olmalı mı?
Todd

@Todd Olmaması daha iyi. sizeof *studentsaynı şeydir ve ÖĞRENCİ'nin değişmesi yanlış olmayacaktır.
trentcl

@trentcl {numStudents} miktarda işaretçi için bellek ayırdı. Yapılar değil, işaretçiler. İşaretçi boyutu genellikle 4 bayttır, bu arada yapının boyutu 20 bayttır. 20 bayt, 4'e bölünebilen sayıdır, bu nedenle doldurmaya gerek yoktur ve yapı, başlangıç ​​adresinden itibaren her 20 baytta depolanır. Yalnızca belirli bir durum için bellek ayırdığınız için çalışır. Aksi takdirde, diğer malloc'lar yapılarınızın hafızasının üzerine yazabilir çünkü tahsis edilmemiştir ve öğrenci hafızanızı aşmışsınızdır.
John Smith

3
@JohnSmith Yanılıyorsunuz; tekrar oku. işaret edilen şeyinsizeof *students boyutu , yani değil . Deyimin koruması gereken hatayı yapıyorsun . Buradan kontrol edin (modern bilgisayarların çoğu gibi sunucunun 8 baytlık işaretçilerine sahip olduğunu ve boyutların 4 ve 20 yerine 8 ve 32 olduğunu unutmayın). sizeof(STUDENT)sizeof(STUDENT*)ptr = malloc(num * sizeof *ptr)
trentcl

@trentcl Açıklama için teşekkürler. Kendi başlatmasındaki başvuruyu kaldırma işaretçisinin sözdizimi kafamı karıştırdı. Biraz kafa karıştırıcı olduğunu söyleyebilirim ama kesinlikle daha kompakt bir çözüm.
John Smith

8

hareket

struct body bodies[n];

sonrasına

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

Dinlenme her şey yolunda görünüyor.


6

Bir yapı dizisini başlatmanın başka bir yolu, dizi üyelerini açıkça başlatmaktır. Çok fazla yapı ve dizi üyesi yoksa bu yaklaşım kullanışlı ve basittir.

Bir struct değişkenini her bildirdiğinizde ifadeyi typedefyeniden kullanmaktan kaçınmak için belirticiyi kullanın struct:

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

Ardından yapılar dizinizi bildirin. Her elemanın ilklendirilmesi, bildirimle birlikte gider:

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}};

Tekrarlamak gerekirse, eğer çok fazla dizi elemanınız ve büyük yapı üyeleriniz yoksa ve belirttiğiniz gibi daha dinamik bir yaklaşımla ilgilenmiyorsanız, bu oldukça basit ve anlaşılır bir çözümdür. Bu yaklaşım, yapı üyeleri adlandırılmış enum değişkenleriyle (ve sadece yukarıdaki örnekteki gibi sayılarla değil) ilklendirildiyse de yararlı olabilir; böylece kod okuyucuya bir yapının amacı ve işlevi hakkında daha iyi bir genel bakış sağlar ve bazı üyeler uygulamalar.


1
Bunu sev! Güzel ve basit cevap 👍
Ethan,

1

Derleyici size bir başlık dosyasında yapının tanımı var söylüyorsun beri yapılar dizisi ilanından önce yapı tipine tanımını bulmak mümkün değildir ve hata olduğunu bu hata araçlarının nbody.csonra başlık dosyasını doğru ekleyip eklemediğinizi kontrol etmelisiniz. Sizin #include'lerinizi kontrol edin ve bu türden herhangi bir değişkeni bildirmeden önce yapının tanımının yapıldığından emin olun.


OP'nin başlık dosyası olarak başlık anlamına geldiğinden şüpheliyim, yazdığı gibi, nbody.c dosyasında bulunan struct dizi bildiriminden önce "aşağıdaki satır yukarıdaki satırın üstündedir". Onun uyanmasını ve şüpheyi gidermesini bekleyelim.
NIMS

@nims doğru, başlık ile mainifadenin üstündeki alanı kastetmiştim .
Amndeep7

1

İşaretçiler kullanarak çözüm:

#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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.