Прочитать текст из списка телефонной книги и добавить в структуру - PullRequest
0 голосов
/ 10 октября 2019

Я пытаюсь прочитать из файла "pb_List.txt", который содержит:

Джон: 789-654-3210
Счет: 852-123-4567
Эми: 963-321-0000

Мне нужно добавить содержимое имени и номера в структуру телефонной книги "pb"

struct phonebook{
    char name[value_size];
    char phone[value_size];
}

struct phonebook pb[book_size];

ОБНОВЛЕНИЕ:

void addFile(){
    File *pb_List;
    pb_List = fopen("pb_List.txt", "r");

    char name[value_size];
    char phone[value_size];

    fscanf(pb_List, "%s %s", name, phone);
    strcpy(pb[size].name, name);
    strcpy(pb[size].phone, phone);
    size++
 }

Я смог добавить первую строку, но моя функция, очевидно, не выполняет итерацию к следующей строке. Как мой цикл покажет это?

1 Ответ

1 голос
/ 10 октября 2019

Так что я решил продолжить писать почти полную программу для вашей проблемы. Таким образом, я обновил этот ответ полным примером того, как использовать мой оригинальный ответ в программе. Ниже кода моего исходного ответа приведен фактический код работающей программы.

Для вашего кода я не думаю, что имя и телефон "телефонной книги" должны быть массивом, но должны указывать намассивы символов. Это потому, что если у вас есть большая программа, даже если вы даете размер, который всегда больше необходимого размера, или работаете с версией «c», которая позволяет динамическое выделение массива во время выполнения, вы можете столкнуться с проблемой исчерпаниястека памяти.

Тем не менее, этот код ниже является примером и предназначен для анализа только одной строки. В реальном случае вы должны корректно изменить код, чтобы использовать его в цикле. Для процедур, вы просто ищите местоположение ":". Если вы нашли это, ищите местоположение нулевого символа (конец строки). Я поместил комментарии в коде, поэтому я не буду здесь много объяснять.

Кроме того, вам следует подумать о том, чтобы pb был динамическим с помощью calloc () и realloc (). Кроме того, calloc () и realloc () не всегда работают. Вы также можете использовать malloc (), но вы должны сами ввести нулевой символ.

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

struct phonebook{
    char * name;
    char * phone;
};

int main(void) {
  char * line = "John:789-654-3210";
  char c;

  // search for the :
  struct phonebook pb[1];
  int dotloc = -1;
  int endloc = 0;
  int recordIndex = 0;

  // Find the dot first
  // and then end line.
  // This could be done in one loop
  // But split into two 
  for ( int i = 0; ; i++) {
    if( line[i] == ':' ) {
      dotloc = i;
      break;
    }
    if( line[i] == '\0' ) break;
  }

  // If found : then that is valid
  if ( dotloc > -1 ){
    for( int i = dotloc + 1; ; i++){
      if( line[i] == '\0' ){
        endloc = i;
        break;  
      }
    }

    // Positioning
    // If : is at pos, there is 5 char in the string
    // add + for null char.
    // If : is at 0 there isn't a char but when calloc still need one for the null char. Empty string.
    pb[recordIndex].name = (char*) calloc(dotloc + 1, sizeof(char));

    // If : is at 5 and end is at 10, there is only 4 char in between but add keep five because of end char.
    pb[recordIndex].phone = (char*) calloc(endloc - dotloc, sizeof(char));

    // Memory allocation fail.
    // Do something else.
    if( pb[recordIndex].name == NULL ) return 1;
    if( pb[recordIndex].phone == NULL ) return 1;

    // copy from line[0] to dotloc location as how many chars.
    // if dotloc is 0, nothing will be copy.
    // null char is already appended by calloc.
    memcpy(pb[recordIndex].name, line, dotloc * sizeof(char));

    // copy from the location of where dotloc is plus 1
    // how many char is base on where endloc is - dotloc 
    // -1
    // If endloc at 1 and dot loc is at 0(next to), nothing to be copy.
    memcpy(pb[recordIndex].phone, &line[dotloc + 1], (endloc - dotloc - 1));
    recordIndex++;
  }

  printf("%s\n", pb[0].name);
  printf("%s", pb[0].phone);

  // Sometimes you need to free memory properly.
  // depend on which system you target or your use case.
  free(pb[0].name);
  free(pb[0].phone);
  return 0;
}

Я не буду подробно объяснять, что делает каждая функция в программе, как ключевой момент, уже упомянутый выше, и на это может потребоваться несколько часов. Эта программа ниже демонстрирует, как использовать мой оригинальный ответ.

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

struct phoneRecord{
    char * name;
    char * phone;
};

struct phoneBook{
    struct phoneRecord * record;
    int length;
    int size;
};

struct phoneBook newBook(){
    // change init_size to 1 for debugging
    int init_size = 30;
    static size_t recordSize = sizeof(struct phoneRecord);
    struct phoneBook output;

    output.record = (struct phoneRecord*) malloc( init_size * recordSize);
    output.length = 0;
    output.size = init_size;

    return output;
}

void freeBook( struct phoneBook * pb){
    for ( int i = 0; i < pb->length; i++ ){
        free(pb->record[i].name);
        free(pb->record[i].phone);
    }
    free(pb->record);
    pb->record = NULL;
    pb->length = 0;
    pb->size = 0;
}

// 0 for success
// 1 for error
int increaseBookSize(struct phoneBook * pb){
    if ( pb == NULL ) return 1;
    static size_t recordSize = sizeof(struct phoneRecord);
    const int newSize = pb->size * 2;
    if ( newSize == 0 ) return 1;

    struct phoneRecord * tempPointer = (struct phoneRecord*) realloc(pb->record, newSize * recordSize);

    if ( tempPointer != NULL ) {
        pb->record = tempPointer;
        pb->size = newSize;
        return 0;
    }
    return 1;
}

// Return - 1 for error.
// Return 0 for no record found or no dot.
// Return 1 for record found.
int getRecord( const char * line, struct phoneRecord * pr){
  // Null check
  if ( pr == NULL ) return -1;

  int dotloc = -1;
  int endloc = 0;

  for ( int i = 0; ; i++) {
    if( line[i] == ':' ) {
      dotloc = i;
      break;
    }
    if( line[i] == '\0' ) break;
  }

  if ( dotloc > -1 ){
    for( int i = dotloc + 1; ; i++){
      if( line[i] == '\0' ){
        endloc = i;
        break;  
      }
    }

    pr->name = (char*) calloc(dotloc + 1, sizeof(char));
    pr->phone = (char*) calloc(endloc - dotloc, sizeof(char));

    if( pr->name == NULL ) return -1;
    if( pr->phone == NULL ) return -1;

    memcpy(pr->name, line, dotloc * sizeof(char));

    memcpy(pr->phone, &line[dotloc + 1], (endloc - dotloc - 1));
    return 1;
  }
  return 0;
}

int main(void) {
    struct phoneBook pb = newBook();
    const char * fileName = "test.txt";
    char * line = NULL;
    FILE *fp;
    size_t len = 0;
    int recordReturnCode;

    fp = fopen(fileName, "r");
    if (fp == NULL){
        printf("Couldn't open file %s.\n", fileName);
        return 1;
    }

    while (getline(&line, &len, fp) != -1) {
        if ( pb.length >= pb.size ) { 
            if ( increaseBookSize(&pb) != 0 ) {
                printf("Something is wrong with getting more memory for the book. However, still print out what already got.\n");
                break;
            }
        }
        recordReturnCode = getRecord(line, &pb.record[pb.length]);

        if ( recordReturnCode == 1 ) pb.length++;
        if ( recordReturnCode == -1 ){
            printf("Something is wrong with getting the record. Clean up and exit.\n");
            freeBook(&pb);
            free(line);
            return 1;
        }
    }
    free(line);

    printf("Print phonebook size for debuging. Size: %d\n", pb.size);
    printf("Read file '%s' and found %d records. Printing each record.\n\n", fileName, pb.length);

    for ( int i = 0; i < pb.length; i++ ){
        printf("Record: %d | Name: %s | Phone: %s", i, pb.record[i].name, pb.record[i].phone);
    }

    freeBook(&pb);
    printf("\n\nChecking book after free. Length: %d, Size: %d", pb.length, pb.size);
    if ( pb.record == NULL ) printf("\nPhonebook free properly, record is NULL.");
    return 0;
}

test.txt content:

John:789-654-3210
Bill:852-123-4567
This is not a valid record
Amy:963-321-0000

AfterEmpty:123-456-789
:###-###-####
noNumber:
Kevin:123-123-1234
...