2016-06-14 13 views
7

Tôi đang cố gắng viết và đọc danh sách được liên kết từ tệp nhị phân trong C. Mục đích của tôi là lưu và tải dữ liệu thường trú cho Nhà Điều dưỡng (thực sự, Tôi là một y tá), để phân loại từng cư dân thông qua các nhóm sử dụng tài nguyên. Tôi đã thực hiện nó cho một số lượng cố định cư dân (32, đó là năng lực của cơ sở) bằng cách sử dụng một loạt các cấu trúc, nhưng bây giờ tôi cần phải làm như vậy cho một tập hợp các cư dân, để thực hiện một nghiên cứu thống kê . Rõ ràng cho lần thử đầu tiên này, tôi đã đơn giản hóa cấu trúc ở mức tối thiểu, vì cấu trúc thực tế chứa 109 dữ liệu.lưu và tải danh sách được liên kết vào tệp nhị phân (C)

Tôi rất gần với giải pháp nhưng một cái gì đó không hoạt động, tức là, mỗi phần tử của danh sách được lưu được xen kẽ với một void. Mã này sẽ đọc danh sách từ tệp nhị phân, hiển thị nó trên thiết bị đầu cuối, thêm một phần tử mới, lưu danh sách. Tất nhiên, mỗi thủ tục nên được đặt trong một hàm.

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

struct pat 
{ 
    char surn [16]; 
    char name [16]; 
    struct pat *next; 
}; 

static FILE *h; 
static struct pat *osp; 
static struct pat *first; 

struct pat *make_structure (void); 

int main() 
{ 
    initscr(); 
    raw(); 
    keypad (stdscr, TRUE); 
    noecho(); 

    clear(); 

    osp=make_structure(); 
    first=osp; 

    h=fopen ("archivio","r"); 

    if (h==NULL) 
     printw ("Archivio inesistente\n"); 
    else 
    { 
     while (!feof(h)) 
     { 
      printw ("Lungh. nome = %d\n",sizeof osp->name); 
      fread (osp->surn,sizeof osp->surn,1,h); 
      fread (osp->name,sizeof osp->name,1,h); 
      printw ("Cognome: %s\tNome: %s\n",osp->surn,osp->name); 
      osp->next=make_structure(); 
      osp=osp->next; 
     } 
    } 

    getch(); 

    echo(); 
    printw ("Surname: "); 
    scanw ("%s",osp->surn); 
    printw ("\nName: "); 
    scanw ("%s",osp->name); 

    noecho(); 

    osp=first; 

    h=fopen ("archivio","w"); 

    while (osp != NULL) 
    { 
     fwrite (osp->surn,sizeof osp->surn,1,h); 
     fwrite (osp->name,sizeof osp->name,1,h); 
     osp=osp->next; 
    } 

    return 0; 
} 

struct pat *make_structure(void) 
{ 
    struct pat *a; 
    a = (struct pat *)malloc(sizeof(struct pat)); 
    return (a); 
} 
+2

Bạn nên đóng các tệp, đặc biệt là trước khi bạn mở lại chúng. (Điều này không nên khắc phục vấn đề của bạn, chỉ cần một mẹo.) – Jashaszun

+1

'scanw ("% s ", osp-> name);' cần giới hạn để tránh đọc quá nhiều ký tự. Với 'name [16]', có thể một cái gì đó như 'scanw ("% 15s ", osp-> name);' – chux

+2

BTW: tên và họ cuối cùng có dấu cách trong đó làm cho '"% s "' không đầy đủ. – chux

Trả lời

2

Bạn đã rất gần, tôi thậm chí không chắc chắn nguyên nhân thực sự của sự thất bại là gì, bởi vì, đối với việc cắt giảm đầu tiên, tôi chỉ áp dụng [hầu hết] các bản sửa lỗi được đề xuất bởi người khác và có một chương trình làm việc .

Mặc dù nó hoạt động, tôi thấy rằng cách bạn thực hiện cuộc gọi "một trước" make_structure sẽ kém linh hoạt hơn khi bạn mở rộng chương trình để thực hiện những việc khác. Ví dụ: bạn sẽ có bản ghi "ma" treo nếu thay vì thêm bản ghi mới, bạn quyết định không thêm thêm bản ghi mới, nhưng thực hiện một số thống kê hoặc thao tác các bản ghi hiện có.

Vì vậy, tôi đã tạo phiên bản thứ hai của chương trình có tính cách ly và tổng quát hơn.


Dưới đây là phiên bản thay đổi tối thiểu [xin vui lòng tha thứ cho việc dọn dẹp phong cách vu vơ]:

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

struct pat { 
    char surn[16]; 
    char name[16]; 
    struct pat *next; 
}; 

static FILE *h; 
static struct pat *osp; 
static struct pat *first; 

struct pat *make_structure(void); 

int 
main() 
{ 
    int rlen; 

    initscr(); 
    raw(); 
    keypad(stdscr, TRUE); 
    noecho(); 

    clear(); 

    osp = make_structure(); 
    first = osp; 

    h = fopen("archivio", "r"); 

    if (h == NULL) 
     printw("Archivio inesistente\n"); 
    else { 
     while (1) { 
      printw("Lungh. nome = %d\n", sizeof osp->name); 

      // leave early on EOF or badly formed entry 
      rlen = fread(osp->surn, sizeof osp->surn, 1, h); 
      if (rlen != 1) 
       break; 

      // leave early on EOF or badly formed entry 
      fread(osp->name, sizeof osp->name, 1, h); 
      if (rlen != 1) 
       break; 

      printw("Cognome: %s\tNome: %s\n", osp->surn, osp->name); 

      osp->next = make_structure(); 
      osp = osp->next; 
     } 
     fclose(h); 
    } 

    // NOTE: this just chews the first character (debug, I suppose?) 
#if 0 
    getch(); 
#endif 

    // add new element 
    echo(); 
    printw("Surname: "); 
    scanw("%15s", osp->surn); 
    printw("Name: "); 
    scanw("%15s", osp->name); 

    noecho(); 

    h = fopen("archivio", "w"); 

    osp = first; 
    while (osp != NULL) { 
     fwrite(osp->surn, sizeof osp->surn, 1, h); 
     fwrite(osp->name, sizeof osp->name, 1, h); 
     osp = osp->next; 
    } 

    fclose(h); 

    return 0; 
} 

struct pat * 
make_structure(void) 
{ 
    struct pat *a; 

    a = malloc(sizeof(struct pat)); 

    // NOTE: do this for good measure 
    a->next = NULL; 

    return (a); 
} 

Dưới đây là phiên bản tổng quát hơn có thể cung cấp cho bạn một số ý tưởng khi bạn mở rộng khả năng của chương trình :

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

struct pat { 
    char surn[16]; 
    char name[16]; 
    struct pat *next; 
}; 

static FILE *h; 
static struct pat *osp; 
static struct pat *first; 
static struct pat *prev; 

void read_archive(const char *file); 
void add_new_elements(void); 
void write_archive(const char *file); 
struct pat *make_structure(void); 
void add_to_list(struct pat *pat); 

int 
main() 
{ 

    initscr(); 
    raw(); 
    keypad(stdscr, TRUE); 
    noecho(); 

    clear(); 

    read_archive("archivio"); 

    // NOTE: this just chews the first character (debug, I suppose?) 
#if 0 
    getch(); 
#endif 

    // NOTE: instead of just automatically adding new elements, this might 
    // be replaced with a menu, such as: 
    // Enter Operation: 
    //  (1) Add new names 
    //  (2) Calculate statistics 
    //  (3) Backup database 
    add_new_elements(); 

    write_archive("archivio"); 

    return 0; 
} 

// read_archive -- read in archive 
void 
read_archive(const char *file) 
{ 
    int rlen; 

    h = fopen(file, "r"); 

    if (h == NULL) 
     printw("Archivio inesistente\n"); 

    else { 
     while (1) { 
      osp = make_structure(); 

      // leave early on EOF or badly formed entry 
      rlen = fread(osp->surn, sizeof osp->surn, 1, h); 
      if (rlen != 1) 
       break; 

      // leave early on EOF or badly formed entry 
      fread(osp->name, sizeof osp->name, 1, h); 
      if (rlen != 1) 
       break; 

      printw("Cognome: %s\tNome: %s\n", osp->surn, osp->name); 

      add_to_list(osp); 
     } 

     // NOTE: this is _always_ for EOF or bad entry, so free it 
     free(osp); 

     fclose(h); 
    } 
} 

// add_new_elements -- prompt for new elements 
void 
add_new_elements(void) 
{ 

    echo(); 
    while (1) { 
     osp = make_structure(); 

     printw("Surname: "); 
     osp->surn[0] = 0; 
     scanw("%15s", osp->surn); 
     if (osp->surn[0] == 0) 
      break; 

     printw("Name: "); 
     osp->name[0] = 0; 
     scanw("%15s", osp->name); 
     if (osp->name[0] == 0) 
      break; 

     add_to_list(osp); 
    } 
    noecho(); 

    free(osp); 
} 

// write_archive -- write out archive 
void 
write_archive(const char *file) 
{ 

    h = fopen(file, "w"); 

    for (osp = first; osp != NULL; osp = osp->next) { 
     fwrite(osp->surn, sizeof osp->surn, 1, h); 
     fwrite(osp->name, sizeof osp->name, 1, h); 
    } 

    fclose(h); 
} 

struct pat * 
make_structure(void) 
{ 
    struct pat *a; 

    a = malloc(sizeof(struct pat)); 

    // NOTE: do this for good measure 
    a->next = NULL; 

    return (a); 
} 

void 
add_to_list(struct pat *pat) 
{ 

    if (first == NULL) 
     first = pat; 
    else 
     prev->next = pat; 

    prev = pat; 
} 

UPDATE:

tôi vẫn cố gắng tìm ra nguyên nhân của sự thất bại của tôi

Tôi không debug/đơn bước mã ban đầu của bạn bởi vì tôi nghĩ rằng logic danh sách liên kết của bạn sẽ cần sửa chữa và tôi muốn đến đó nhanh chóng. Tuy nhiên, sau khi tôi xem xét nó, logic vẫn ổn. Dựa trên phân tích phỏng đoán tốt nhất của tôi, lỗi có thể xảy ra là feof mà tôi đã thay đổi để kiểm tra độ dài trên fread.

Tất nhiên tôi sẽ tổ chức tốt hơn các chương trình sử dụng các hàm

Tôi cho rằng bạn sẽ. Sự phân chia trong chương trình thứ hai là nhiều hơn của một công cụ giảng dạy để làm rõ và minh họa một nguyên tắc và là không phải là một phê bình về tính mô-đun.

Trong mã ban đầu của bạn, bạn để thêm bản ghi mới vì osp trống nhưng đã được liên kết trong danh sách. Một cách lỏng lẻo, một kỷ lục "zombie", nếu bạn muốn.

Tức là danh sách có mục nhập được liên kết trong trước nó đã được điền và xác thực. Nói cách khác, sau vòng lặp đọc, nhưng trước khi người dùng được nhắc về mục nhập mới, danh sách có thể bị coi là không đúng định dạng (nghĩa là vi phạm "nhỏ" lập trình hợp đồng hoặc "thiết kế theo hợp đồng") .

Chức năng tách trong chương trình thứ hai chỉ là nhấn mạnh điều này. Đặc biệt, bằng cách di chuyển vòng lặp đọc đến một hàm riêng biệt, nó minh họa/thực thi thiết kế theo hợp đồng.

Tức là, khi nhập cảnh, danh sách là toàn bộ và được hình thành tốt [mặc dù, trống]. Khi trả lại, nó hoặc là trống rỗng [nếu tệp đầu vào không không phải là tồn tại] hoặc chỉ có các bản ghi hoàn chỉnh/được hoàn thành trong đó.

Trong chương trình thứ hai, mục nhập một phần/không đúng định dạng là không bao giờ được liên kết. add_to_list luôn được thực hiện lần cuối [chỉ cho toàn bộ/toàn bộ bản ghi].

Vì vậy, đối với cả hai số read_archiveadd_new_entries, khi chúng được gọi, cả hai đều được cung cấp danh sách toàn bộ/hoàn chỉnh chỉ với các bản ghi hợp lệ hoàn chỉnh. Đó là "hợp đồng" với chúng.

Và để hoàn thành một phần của "hợp đồng", các chức năng này phải để mọi thứ theo cùng một cách, duy trì tính toàn vẹn của danh sách khi thoát. Đó là 'hợp đồng' của các chức năng với thế giới bên ngoài


CẬP NHẬT # 2:

tha cho tôi cho Cựu Ước, nhưng bạn có thể gợi ý cho tôi một IDE tốt cho C - C++ hoạt động tốt với Debian/GNU Linux?

Tôi có thể không phải là người tốt nhất khuyên bạn về điều này vì tôi không sử dụng. Tôi đã viết C rất lâu trước khi chúng tồn tại, vì vậy tôi đã phát triển bộ công cụ của riêng mình, nó mạnh mẽ hơn nhiều so với bất kỳ IDE nào mà tôi từng thấy. Ngoài ra, khi tôi nhìn vào chúng, tôi không bao giờ có thể tìm được cách để kết nối cả hai.

tôi đang ở nhà với Code :: Blocks, nhưng tiếc là cái gọi là đêm xây dựng là lỗi và tai nạn rất thường xuyên

Nếu bạn đang ở nhà với CodeBlocks, nhưng đêm xây dựng là lỗi, có lẽ giải pháp đơn giản là chuyển bản cập nhật của bạn sang cây "ổn định", nếu có thể. Đó có thể là "câu trả lời ngắn" tốt nhất.

(tiện ích hoàn thành mã rất hữu ích nhưng tôi không được gõ str ..., nếu không nó bị đóng băng) và điều đó rất bực bội!

Có thể bạn có thể kiểm tra cơ sở dữ liệu lỗi và xem liệu sự cố bạn gặp phải có báo cáo lỗi đã biết hay không. Nếu không, bạn có thể/nên nộp một.


Tôi đã cài đặt codeblocks. Nó trông sạch sẽ và đơn giản, đủ. Tôi cũng đã cài đặt eclipse và xem kdevelop. Từ một số trang web, nhật thực được đánh dấu cao, với netbeans đóng một giây thứ hai

Tôi đã cố gắng sử dụng chúng trên tệp nguồn tôi đã nằm xung quanh được xây dựng bằng Makefile. codeblocks đủ trực quan để tôi có thể làm nó nhanh chóng. Tôi gặp rắc rối với những người khác. eclipse ban đầu được thiết kế bởi IBM để sử dụng nội bộ và sau đó được phát hành như một dịch vụ công cộng. Nó được hỗ trợ tốt và trưởng thành.

Tôi đã chạy eclipse mà không CDT, nhưng một khi tôi nói thêm rằng, eclipse được phiếu bầu của tôi, bởi vì nó dường như có đủ các tính năng kiểm soát tất cả những gì tôi sẽ để phàn nàn về dưới đây ;-)

Một IDE là một lựa chọn hơi cá nhân [trừ khi công ty bạn ủy quyền một], vì vậy bạn nên sử dụng những gì bạn thích. Nói cách khác, hãy thử một số và xem những tính năng nào họ có và cách chúng hoạt động. Đây là trang liệt kê một số: https://en.wikipedia.org/wiki/Comparison_of_integrated_development_environments

Khi chọn IDE, bạn phải xem xét các tính năng "được sử dụng nhiều nhất". Điều thường xuyên nhất bạn làm là cuộn xung quanh trong tệp nguồn. Vì vậy, trình chỉnh sửa phải hỗ trợ bí danh hjkl cho các phím mũi tên, chẳng hạn như vi. Có để di chuyển bàn tay phải của bạn qua các phím mũi tên và trở lại làm chậm những thứ xuống rất nhiều mà nó không khởi động.

sử dụng nhật thực gvim [đồ họa vim], vì vậy đó là dấu cộng.

Tôi là không một người hâm mộ chỉnh sửa với một số cửa sổ soạn thảo WYSIWYG đơn giản chỉ có các tính năng tìm kiếm/thay thế thô. Tương tự như vậy, vim cho phép tìm kiếm regex chỉ đơn giản bằng cách gõ /, vì vậy một lần nữa, các hoạt động phổ biến nhất là "trong tầm tay của bạn"

tôi không sử dụng [cũng không muốn] autocompletion tính năng. Khi tôi đã thử họ, họ thường xuyên nhận được những điều sai trái và phải mất nhiều thời gian để backspace hơn những gì họ đã làm. Tôi là một người đánh máy rất nhanh.

Tôi cũng tắt tính năng tô sáng và tô màu cú pháp của nguồn. Khi nhập mã nguồn, màu sắc thay đổi chỉ với mỗi ký tự được nhập vì biên tập viên cho rằng Tôi đang nhập (ví dụ: tôi đang nhập nhận xét, nhưng nó cho rằng đó là mã, v.v.) mất tập trung.

Ngoài ra, khi xem kết quả cuối cùng, tôi thấy rằng kết quả được tô màu là "quá bận" (tức là tôi cần phải lọc thêm thông tin) thay vì điều gì đó giúp tôi xem những gì tôi cần xem.

Tôi khá khăng khăng về thụt lề, chia nhỏ các khối mã dài với các dòng trống để cải thiện khả năng đọc. Và, tất nhiên, ý kiến ​​tốt. Đối với tôi, chúng quan trọng hơn nhiều so với màu. Tôi có một công cụ tùy chỉnh cho thụt lề [Như bạn có thể nhớ lại, khi tôi đăng mã ở trên, nó đã được reindented vì tôi chạy nó thông qua công cụ của tôi trước khi đăng bài.

Một tính năng khác là trình gỡ lỗi đồ họa. Nó có đầy đủ tính năng không? Ví dụ: ddd là trình bao bọc đồ họa xung quanh [rất mạnh] gdb.ddd cung cấp trình bao bọc đồ họa và cửa sổ cho những thứ thông thường nhưng vẫn cho phép cửa sổ văn bản trực tiếp hiển thị lời nhắc gdb, vì vậy bạn có thể nhập thủ công các lệnh nâng cao hơn (ví dụ: watch symbol).

IDE có thể mở rộng không? Bạn có thể thêm các plugin không? Bạn có thể dễ dàng thêm/tạo của riêng bạn?

IDE sử dụng hệ thống kiểm soát mã nguồn nào? Tôi đã sử dụng nhiều trong nhiều năm và, hiện tại, được bán hoàn toàn trên git. Vì vậy, nếu IDE không hỗ trợ git, nó không phải là khởi động.

Cần lưu ý rằng gitnên tính năng nhiều hơn những gì họ có thể không được chứa trong một GUI. Vì vậy, các công cụ thực sự mạnh mẽ sử dụng một công cụ dòng lệnh trong một cửa sổ thiết bị đầu cuối.

IDE của tôi? Một số cửa sổ xterm, vi, git và bộ công cụ của tôi [hiện tại là 250.000 dòng của perl tập lệnh ;-)] IDE có buộc bạn thực hiện theo cách của nó không? Việc nhập/xuất cấu hình, vv dễ dàng như thế nào với các công cụ và IDE bên ngoài khác?

Tôi có một kịch bản xây dựng rất mạnh mẽ về thiết kế của riêng tôi. Vì vậy, tôi muốn IDE, khi tôi nhấp vào nút "xây dựng" để không làm bất cứ điều gì bình thường, nhưng chuyển quyền kiểm soát sang kịch bản xây dựng của tôi. Tương tự như vậy cho bất kỳ hoạt động nào khác mà IDE cung cấp là.

IDE có thể di động và có sẵn trên tất cả các nền tảng chính: linux, OSX và windows không? Trong quá khứ, đó là một lý do khác mà tôi tránh xa các IDE. Chúng sẽ chỉ có sẵn trên một nền tảng. Hoặc, kể từ khi tôi đang làm công việc tư vấn, tôi sẽ đi vào một môi trường mà sẽ không cho phép cài đặt/sử dụng IDE vì chính sách [sysadmin].

+0

Cảm ơn bạn rất nhiều! Bạn rất tử tế. Tôi đã không mong đợi sớm như vậy một asnwer. Tất nhiên tôi sẽ tổ chức tốt hơn chương trình bằng cách sử dụng các chức năng, nhưng tôi vẫn đang cố gắng tìm ra nguyên nhân thất bại của mình: sau cùng, đó là lần đầu tiên của tôi, nhưng tôi không biết liệu tôi có thành công không Cứu giúp. Xin lỗi vì những từ tiếng Ý trong mã. Theo như các mối quan tâm getch(), có, mục đích của nó chỉ là gỡ lỗi. – user241968

+0

Bạn được chào đón! Một trong những người bạn tốt nhất của tôi là một y tá và cô ấy phân tích tương tự hồ sơ bệnh án, vì vậy tôi có thể cảm thông. Bạn tôi không phải là lập trình viên và chỉ sử dụng bảng tính, v.v., vì vậy, với bạn, với tư cách là một y tá, hãy viết chương trình của riêng bạn [trong C, không ít hơn] sẽ được khen thưởng. Tôi đã thực hiện cắt và dán ngôn ngữ ["ngoài hành tinh" :-)] vào Google Dịch, vì vậy tôi đã có thể đọc đủ tiếng Ý để hiểu những gì đang diễn ra. Tôi đã thêm bản cập nhật cho câu trả lời của mình để làm rõ mọi thứ hơn một chút. Hãy tiếp tục phát huy! –

+0

Phiên bản thứ hai trong 'read_archive', bạn có' h = fopen (tập tin, "w"); '(' "w" '??) –

Các vấn đề liên quan