เพิ่มขนาดอาร์เรย์แบบไดนามิกใน Struct C

คำถามของฉันง่าย ๆ ... ฉันมีการประกาศโครงสร้างดังต่อไปนี้:

struct Address {
   int id;
   int set;
   char *name;
   char *email;
};

struct Database {
   struct Address rows[512];
};

struct Connection {
   FILE *file;
   struct Database *db;
};

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

void Database_write(struct Connection *conn){
   rewind(conn->file);

   int rc = fwrite(conn->db, sizeof(struct Database), 1, conn->file);
      if(rc != 1){
         die("Failed to write database.\n",conn);
      }

   rc = fflush(conn->file);
      if(rc == -1){
         die("Cannot flush database.\n",conn);
      }

ทุกอย่างใช้งานได้ดีเมื่อฉันมีจำนวนแถวที่กำหนดไว้ล่วงหน้าภายในโครงสร้าง "ฐานข้อมูล" สำหรับที่อยู่ของฉัน เช่น 512 แต่ถ้าฉันต้องการสร้างจำนวนแถวแบบไดนามิกล่ะ เหมือนกับที่พารามิเตอร์ส่งผ่านไปยังฟังก์ชันเหรอ? ฉันได้ลองใช้สิ่งต่อไปนี้...

struct Database {
   struct Address *rows;
};

และจัดสรรพื้นที่ให้กับพอยน์เตอร์นี้ด้วย:

conn->db->rows = (struct Address*) malloc(sizeof(struct Address)*max_rows);

โดยที่ max_rows เป็นพารามิเตอร์ที่ส่งผ่านไปยังฟังก์ชัน...แต่ตอนนี้ปัญหาก็คือเมื่อฉันลองบันทึกสิ่งนี้ลงในไฟล์ภายในโครงสร้าง "การเชื่อมต่อ" ของฉัน ฉันแค่บันทึกตัวชี้ "struct Address *rows;" และไม่ใช่ข้อมูลที่จัดสรรพื้นที่ไว้ มีข้อเสนอแนะเกี่ยวกับวิธีการบันทึกพื้นที่ที่จัดสรรนี้หรือมีอาร์เรย์ที่กำหนดไว้ล่วงหน้าภายในโครงสร้างแล้วขยายแบบไดนามิกหรือไม่

ขอบคุณล่วงหน้า!


person Sebastian Serrano    schedule 09.05.2017    source แหล่งที่มา
comment
โค้ดการเขียนที่อัปเดตใหม่ของคุณมีลักษณะอย่างไรที่ใช้งานไม่ได้   -  person Chris Turner    schedule 09.05.2017
comment
คุณ มี เพื่อบันทึกตัวชี้หรือไม่ คุณเพิ่งทิ้งโครงสร้างเพื่อไฟล์เป็นไบต์หรือไม่? นั่นเป็นความคิดที่แย่มาก ไฟล์นั้นจะถูกอ่านอย่างถูกต้องบนชุดย่อยของเครื่องเท่านั้น สิ่งที่คุณต้องการคือการเขียนการแสดงข้อมูลเชิงตรรกะลงในไฟล์ ไม่ใช่แค่ดัมพ์ไบต์ที่อยู่ในหน่วยความจำของกระบวนการของคุณ   -  person StoryTeller - Unslander Monica    schedule 09.05.2017
comment
คุณจะต้องเขียนรูทีนการทำให้เป็นอนุกรมซึ่งจะแยกวิเคราะห์โครงสร้าง   -  person Lundin    schedule 09.05.2017
comment
คุณจำเป็นต้องส่ง malloc() ถึง struct Address * หรือไม่? หรือคุณเพียงทำเพราะคุณเห็นมันที่อื่น? ฉันถามสิ่งนี้เพราะมันจะแตกต่างออกไปมากถ้าคุณต้องแคสต์ มันจะเป็นภาษาที่แตกต่างออกไปโดยสิ้นเชิง นอกจากนี้ conn->db->rows อาจยกเลิกการอ้างอิงตัวชี้ NULL หากคุณไม่ระวัง แล้ว die() คืออะไร มันทำให้โค้ดดูเหมือน PHP และมันคือ PHP ดังนั้นมันคือ PHP   -  person Iharob Al Asimi    schedule 09.05.2017
comment
โครงสร้างทั้งหมดของฉันเหมือนกัน ยกเว้นฐานข้อมูลของฉันซึ่งฉันเปลี่ยนเป็นอันที่ฉันพูดถึงโดยใช้ตัวชี้โครงสร้างที่อยู่ *แถว และพยายามบันทึกสิ่งนี้ด้วย void Database_write เดียวกันและเมื่อฉันพยายามเปิดไฟล์ แน่นอนว่าข้อมูลของฉัน ชี้ไปที่ *rows pointer ของฉันไม่อยู่ที่นั่น :/ และฟังก์ชัน die() ของฉันเป็นเพียงกิจวัตรทั่วไปในการล้างหน่วยความจำที่จัดสรร   -  person Sebastian Serrano    schedule 09.05.2017
comment
มันทำงานอย่างไรก่อนหน้านี้เมื่อ name และ email เป็นตัวชี้ด้วย คุณต้องเขียนเฉพาะข้อความลงในไฟล์หรือทำสิ่งที่ ความคิดเห็นนี้ แนะนำ   -  person Iharob Al Asimi    schedule 09.05.2017
comment
ฟังดูเหมือนเป็นความคิดที่ดี แต่ปัญหาคือฉันไม่รู้ว่าจะต้องทำอย่างไร :/   -  person Sebastian Serrano    schedule 09.05.2017
comment
@IharobAlAsimi Code ต้องการนักแสดงมากหรือน้อยเท่ากับความคิดเห็นเกี่ยวกับการคัดเลือกนักแสดงที่นี่   -  person chux - Reinstate Monica    schedule 09.05.2017


คำตอบ (1)


คุณมาถูกทางแล้วด้วย malloc สำหรับการสร้างจำนวนที่อยู่แบบไดนามิก

conn->db->rows = (struct Address*) malloc(sizeof(struct Address)*max_rows);

แต่แล้วคุณประสบปัญหาในการเขียนข้อมูลเหล่านั้นลงในไฟล์ใน Database_write เนื่องจากโครงสร้างที่จัดสรรแบบไดนามิกไม่มีจำนวนแถวที่เดินสายเข้าไปอีกต่อไป คุณจะต้องเปลี่ยน Database_write เป็น

  1. ผ่านไปกี่แถวที่จะเขียน
  2. ปรับบรรทัด fwrite เพื่อเขียนทุกแถว

คุณมี:

void Database_write(struct Connection *conn)
{
    rewind(conn->file);

    int rc = fwrite(conn->db, sizeof(struct Database), 1, conn->file);
    if(rc != 1){
        die("Failed to write database.\n",conn);
    }
...

ตอนนี้คุณต้องการสิ่งที่ชอบ:

void Database_write(struct Connection *conn, int num_rows)
{
    rewind(conn->file);

    int rc = fwrite(conn->db, sizeof(struct Database), num_rows, conn->file);
    if(rc != num_rows)
    {
        die("Failed to write database.\n",conn);
    }

...

คุณสามารถเพิ่มจำนวนแถวลงในโครงสร้างฐานข้อมูลของคุณเพื่อบันทึกจำนวนแถวที่ควรอยู่ในไฟล์:

struct Database 
{
    int num_rows;
    struct Address *rows;
};

ในกรณีนี้ คุณควร fwrite จำนวนแถวที่จะไฟล์ก่อน จากนั้นจึงเขียน num_rows ของ struct Address

คุณอาจต้องการค้นหา จัดสรรใหม่ เพื่อเปลี่ยนจำนวนแถวได้ทันที คำแนะนำ - ใช้ด้วยความระมัดระวังและใส่ใจกับค่าส่งคืน

person Gavin Shreeves    schedule 09.05.2017