1

This is code for file lib.h

/**
 * @file lib.h
 * @brief Файл с определением функций для решения заданий из лабораторной работы №21
 *
 * @author Taradai S.V.
 * @version 1.0
 * @date 13-май-2021
 */

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#include <regex.h>
#ifdef DEBUG

/** стала для визначення поточного часу та назви функцій*/
static struct tm *debug_tm;

#endif
/** Структура про птахів*/
struct Birds{
  int IsRinged;
  char Specie[50];
  int BirdAge;
  int HomeArea;
  int HomeHeight;
  int HomeFeederQuantity;
  int HomeHasNest;;
  char Gender[10];
};
/** Список */
typedef struct BirdCapsule {
  struct Birds bird;
  struct BirdCapsule *next;
} Bird_t;
/**
Bird_t - Create-function that creates a linked list with N elements in it
@param [N] the quantity of elements in a linked list
@returns [head] the created list
*/
Bird_t * Create(int N);
/**
Export - a function that saves the list into a file
@param [Bird_t *head] linked list
@param [char* filename] a file where the list is stored
@returns [0] properly made function
*/
int Export(Bird_t *head,char* filename);
/**
Import - a function that reads the list from a file and prints all the info inside
@param [Bird_t *head] linked list
@param [char* filename] a file where the list is stored
@returns [0] properly made function
*/
int Import(Bird_t *head, char* filename);
/**
Print_Struct - a function that prints the list on a display
@param [Bird_t *head] linked list
@returns [0] properly made function
*/
int Print_Struct (Bird_t *head);
/**
Get_element_by_pos - a function that prints an element on a position
@param [Bird_t *head] linked list
@param [int pos] a position of element needed to find
@returns [0] properly made function
*/
int Get_element_by_pos(Bird_t *head, int pos);
/**
Add - a function that adds a new element at the end of list
@param [Bird_t *head] linked list
@returns [0] properly made function
*/
int Add (Bird_t *head) ;
/**
Del - a function that adds a new element at the special position of list
@param [Bird_t *head] linked list
@param [int num] the position of
@returns [0] properly made function
*/
int Del (Bird_t *head, int num);
/**
debug_print_fname - a function that prints the present time and the name of function
@param [const char *func_name] the name of function
@returns nothing
*/
void debug_print_fname(const char *func_name);

int regex_scan_element(char *dest_str, const char *pattern);

This is code for file lib.c

/**
 * @file lib.c
 * @brief Файл с реализацией функций для решения заданий из лабораторной работы №21
 *
 * @author Taradai S.V.
 * @version 1.0
 * @date 13-маЙ-2021
 */


#include "lib.h"

Bird_t * Create(int N){
  int r_code;
  char gender[50];
  Bird_t *head=NULL;
  head=malloc(sizeof(Bird_t));
  Bird_t *current=head;
  for(int i=0;i<N;i++){
    current->bird.IsRinged=rand()%2;
    printf("What's the bird specie?:");
    do{
      if(r_code=regex_scan_element(current->bird.Specie,"^[A-Z][a-z_ ]*")==1){
        printf("The string doesn't compare to the standards, please enter a new one");
      }
    } while(r_code==1);
    current->bird.BirdAge=rand()%12+1;
    current->bird.HomeArea=rand()%100+1;
    current->bird.HomeHeight=rand()%100+1;
    current->bird.HomeFeederQuantity=rand()%5;
    current->bird.HomeHasNest=rand()%2;
    printf("What's the bird gender?:");
    do{
      if(r_code=regex_scan_element(current->bird.Gender,"^[A-Z][a-z_ ]*")==1){
        printf("The string doesn't compare to the standards, please enter a new one");
      }
    } while(r_code==1);
    current->next=malloc(sizeof(Bird_t));
    current=current->next;
  }
  return head;
}
int Export(Bird_t *head,char* filename){
  FILE * fp;
  if ((fp = fopen(filename, "wb")) == NULL){
    perror("Error occurred while opening file");
    return 1;
  }
  Bird_t * current = head;
  while (current != NULL) {
        fprintf (fp, "%d%s%d%d%d%d%d%s",
        current -> bird.IsRinged,
        current -> bird.Specie,
        current -> bird.BirdAge,
        current -> bird.HomeArea,
        current -> bird.HomeHeight,
        current -> bird.HomeFeederQuantity,
        current -> bird.HomeHasNest,
        current -> bird.Gender);
        current = current -> next;
        }
    fclose (fp);
  return 0;
}
int Import(Bird_t *head, char* filename){
  FILE * fp;
  if ((fp = fopen(filename, "wb")) == NULL){
    perror("Error occurred while opening file");
    return 1;
  }
  Bird_t * current = head;
  while (current != NULL) {
    fscanf (fp, "%d%s%d%d%d%d%d%s",
        &current -> bird.IsRinged,
        current -> bird.Specie,
        &current -> bird.BirdAge,
        &current -> bird.HomeArea,
        &current -> bird.HomeHeight,
        &current -> bird.HomeFeederQuantity,
        &current -> bird.HomeHasNest,
        current -> bird.Gender);
        current = current -> next;

  }
  Print_Struct (head);
  fclose (fp);
  return 0;
}
int Print_Struct (Bird_t *head) {
    Bird_t * current = head;
        while (current -> next!= NULL) {
                    printf ("\nЧи окольцована птиця(1-так,0-ні):%d", current -> bird.IsRinged);
            printf ("\nНазва виду:%s", current -> bird.Specie);
            printf ("\nВік птаха:%d", current -> bird.BirdAge);
            printf ("\nПлоща домівки(у см:2):%d", current -> bird.HomeArea);
            printf ("\nВисота домівки(у см):%d", current -> bird.HomeHeight);
            printf ("\nКількість годівниць:%d", current -> bird.HomeFeederQuantity);
            printf ("\nЧи є гніздо(1-так,0-ні):%d", current ->  bird.HomeHasNest );
                    printf ("\nГендер:%s", current -> bird.Gender);
        printf ("---------------------------------------\n");
                current = current -> next;
        }
    printf ("\n");
    return 0;
}
int Get_element_by_pos(Bird_t *head, int pos) {
  int originalpos=pos+1;
  Bird_t * current = head;
  while (pos!= 0) {
    current = current->next;
    pos--;
  }
  printf ("\nОсь що ми найшли на %d позиції:",originalpos);
  printf ("\nЧи окольцована птиця(1-так,0-ні):%d", current -> bird.IsRinged);
  printf ("\nНазва виду:%s", current -> bird.Specie);
  printf ("\nВік птаха:%d", current -> bird.BirdAge);
  printf ("\nПлоща домівки(у см:2):%d", current -> bird.HomeArea);
  printf ("\nВисота домівки(у см):%d", current -> bird.HomeHeight);
  printf ("\nКількість годівниць:%d", current -> bird.HomeFeederQuantity);
  printf ("\nЧи є гніздо(1-так,0-ні):%d", current ->    bird.HomeHasNest );
  printf ("\nГендер:%s", current -> bird.Gender);
  return 0;
}
int Add (Bird_t *head) {
        Bird_t * current = head;
    Bird_t * new = Create (1);
    int n = 0;
    while (current != NULL) {
        current = current -> next;
        n++;
    }
    current = head;
    for (int i = 1; i < n; i++) {
        current = current -> next;
    }
    current -> next = new;
    printf (" Елемент спиcку додано в кінець:\n\n");
    Print_Struct (head);
    return 0;
}
int Del (Bird_t *head, int num) {
    Bird_t *current = head;
    Bird_t *memory;
    for (int i = 0; i < num - 1; i++) {
        current = current -> next;
        memory = current -> next;
    }
    free (current);
    current = head;
    for (int i = 0; i < num - 2; i++) {
        current = current -> next;
    }
    current -> next = memory;
    Print_Struct (head);
    return 0;
}

int regex_scan_element(char *dest_str, const char *pattern)
{
 /* Шаблон выражения */
 regex_t regex;
 /* Найденное выражение */
 regmatch_t regmatch;
 /* Код возврата */
 int r_code;
 /* Буфер ввода */
 char str[50];

 /* Считать строку из потока ввода */
 scanf("%s",str);
 str[strcspn(str, "\n")] = '\0';

 /* Инициализация RegEx. Использовать расширенные выражения */
 r_code = regcomp(&regex, pattern, REG_EXTENDED);
 if (r_code != 0) {
  printf("function regcomp failed");
  return 1;
 }
 /* Сравнение строки с форматом */
 r_code = regexec(&regex, str, 1, &regmatch, 0);
 /* Если сравнение завершилось успешно */
 if (r_code == 0) {
  /* Копирование найденной строки в целевую строку */
  strncpy(dest_str, &str[regmatch.rm_so],
   regmatch.rm_eo - regmatch.rm_so);
  *(dest_str + (regmatch.rm_eo - regmatch.rm_so)) = '\0';

  regfree(&regex);
  return str;
 }
 /* Если произошла ошибка */
 if (r_code != REG_NOMATCH) {
  printf("function regexec failed");
  regfree(&regex);
  return 2;
 }
 /* Если совпадений нет */
 regfree(&regex);
 return 1;
}

This is code for file main.c

/**
 * @file main.c
 * @brief Файл с демонстрацией решения заданий из лабораторной работы №22
 *
 * @author Taradai S.V.
 * @version 1.0
 * @date 13-май-2021
 */


#include "lib.c"

int main(){
  char * filename="birds.dat";
  Bird_t *head=NULL;
  head=Create(3);
  Export(head,filename);
  Import(head,filename);
  Get_element_by_pos(head,2);
  Add(head);
  return 0;

}

Well, this program must work in following way:
It must create a list with the N elements in it and when it's a scanf thing. It begins to compare it to the following standards: only Cyrillic or Latin letters, only one space, underline is allowed and all of this must start with the capital letter. Then it must be exported into a file and then imported. The other functions can be untouched by now.
The problem that it hits a segmentation fault in gdb at the following string in function Export():

 Bird_t * current = head;

I can't imagine now what can be the thing, so I call for your help. Can you help me with it?

greybeard
  • 2,249
  • 8
  • 30
  • 66

1 Answers1

0

There were a number of bugs.

Most importantly, whether the head element of the list is a dummy node or contains valid data was not consistent across all functions. See my recent answer: Several problems with Linked Lists functions as the problems there are quite similar to yours.

Create didn't initialize the list properly [so Export would segfault].

Import was opening the file for writing instead of reading so it destroyed the data written by Export. You are not reading/writing binary data, so the files should not be opened with "b".

regex_scan_element wouldn't even compile cleanly because in the success case, it was returning str instead of 0.

Although the format for fscanf in Import is fine, the corresponding format for fprintf in Export must have spaces between the fields


Please do not put spaces around the -> operator. That is tightly bound to its arguments.

Replace all (e.g.):

current = current -> next;

With:

current = current->next;

The Add function had to scan the list twice

Note that the Import function is a bit of a cheat. It is just replacing existing elements of the list. This assumes that the existing list is of the correct length. This won't work too well in the general case. It should remove all elements from the existing list and then read in all [until EOF] and add them to the tail of the empty list.


Here is a cleaned up and refactored version. It is annotated.

It uses cpp conditionals to denote old vs. new code:

#if 0
// old code
#else
// new code
#endif

#if 1
// new code
#endif

For debug, I added some dbgprt macros. And, because it's difficult to debug a program that prompts for input with gdb, I added some code that takes input from a file from argv[1]

Note that I did not fix Import by deleting the list as mentioned above.

Anyway, here is the code:

/**
 * @file lib.h
 * @brief Файл с определением функций для решения заданий из лабораторной работы №21
 *
 * @author Taradai S.V.
 * @version 1.0
 * @date 13-май-2021
 */

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#include <regex.h>

#ifdef DEBUG

/** стала для визначення поточного часу та назви функцій*/
#if 0
static struct tm *debug_tm;
#else
struct tm *debug_tm;
#endif

#define dbgprt(_fmt...) \
    printf(_fmt)

#else
#define dbgprt(_fmt...) \
    do { } while (0)
#endif

#if 1
FILE *fin;
#endif

/** Структура про птахів*/
struct Birds {
  int IsRinged;
  char Specie[50];
  int BirdAge;
  int HomeArea;
  int HomeHeight;
  int HomeFeederQuantity;
  int HomeHasNest;;
  char Gender[10];
};

/** Список */
typedef struct BirdCapsule {
  struct Birds bird;
  struct BirdCapsule *next;
} Bird_t;

/**
Bird_t - Create-function that creates a linked list with N elements in it
@param [N] the quantity of elements in a linked list
@returns [head] the created list
*/
Bird_t * Create(int N);
/**
Export - a function that saves the list into a file
@param [Bird_t *head] linked list
@param [char* filename] a file where the list is stored
@returns [0] properly made function
*/
int Export(Bird_t *head,char* filename);
/**
Import - a function that reads the list from a file and prints all the info inside
@param [Bird_t *head] linked list
@param [char* filename] a file where the list is stored
@returns [0] properly made function
*/
int Import(Bird_t *head, char* filename);
/**
Print_Struct - a function that prints the list on a display
@param [Bird_t *head] linked list
@returns [0] properly made function
*/
int Print_Struct (Bird_t *head);
/**
Get_element_by_pos - a function that prints an element on a position
@param [Bird_t *head] linked list
@param [int pos] a position of element needed to find
@returns [0] properly made function
*/
int Get_element_by_pos(Bird_t *head, int pos);
/**
Add - a function that adds a new element at the end of list
@param [Bird_t *head] linked list
@returns [0] properly made function
*/
int Add (Bird_t *head) ;
/**
Del - a function that adds a new element at the special position of list
@param [Bird_t *head] linked list
@param [int num] the position of
@returns [0] properly made function
*/
int Del (Bird_t *head, int num);
/**
debug_print_fname - a function that prints the present time and the name of function
@param [const char *func_name] the name of function
@returns nothing
*/
void debug_print_fname(const char *func_name);

int regex_scan_element(char *dest_str, const char *pattern);
/**
 * @file lib.c
 * @brief Файл с реализацией функций для решения заданий из лабораторной работы №21
 *
 * @author Taradai S.V.
 * @version 1.0
 * @date 13-маЙ-2021
 */

//#include "lib.h"

Bird_t *
Create(int N)
{
    int r_code;
    //char gender[50];
    Bird_t *prev = NULL;
    Bird_t *head = NULL;

// NOTE/BUG: this assumes a dummy head node but all other functions assume it
// has data in it (except the print function)
#if 0
    head = malloc(sizeof(Bird_t));
    Bird_t *current = head;
#else
    Bird_t *current;
#endif

    for (int i = 0; i < N; i++) {
#if 1
        current = malloc(sizeof(*current));

        if (prev != NULL)
            prev->next = current;
        else
            head = current;

        current->next = NULL;
#endif

        current->bird.IsRinged = rand() % 2;
        printf("What's the bird specie?:");
        do {
#if 0
            if (r_code = regex_scan_element(current->bird.Specie,
                "^[A-Z][a-z_ ]*") == 1) {
                printf("The string doesn't compare to the standards, please enter a new one");
            }
#else
            if ((r_code = regex_scan_element(current->bird.Specie,
                "^[A-Z][a-z_ ]*")) == 1) {
                printf("The string doesn't compare to the standards, please enter a new one");
            }
            dbgprt("r_code=%d\n",r_code);
#ifdef DEBUG
            if (r_code != 0)
                exit(1);
#endif
#endif
        } while (r_code == 1);
        current->bird.BirdAge = rand() % 12 + 1;
        current->bird.HomeArea = rand() % 100 + 1;
        current->bird.HomeHeight = rand() % 100 + 1;
        current->bird.HomeFeederQuantity = rand() % 5;
        current->bird.HomeHasNest = rand() % 2;
        printf("What's the bird gender?:");
        do {
            if ((r_code = regex_scan_element(current->bird.Gender,
                "^[A-Z][a-z_ ]*")) == 1) {
                printf("The string doesn't compare to the standards, please enter a new one");
            }
            dbgprt("r_code=%d\n",r_code);
#ifdef DEBUG
            if (r_code != 0)
                exit(1);
#endif
        } while (r_code == 1);
#if 0
        current->next = malloc(sizeof(Bird_t));
        current = current->next;
#else
        prev = current;
#endif
    }
    return head;
}

int
Export(Bird_t *head, char *filename)
{
    FILE *fp;

// NOTE/BUG: open for text _not_ binary
#if 0
    if ((fp = fopen(filename, "wb")) == NULL) {
#else
    if ((fp = fopen(filename, "w")) == NULL) {
#endif
        perror("Error occurred while opening file");
        return 1;
    }
    Bird_t *current = head;

    while (current != NULL) {
        dbgprt("Export: %s\n",current->bird.Specie);
// NOTE/BUG: format will _not_ be readable by scanf -- numbers must be separated
// by spaces
#if 0
        fprintf(fp, "%d%s%d%d%d%d%d%s",
#else
        fprintf(fp, "%d %s %d %d %d %d %d %s\n",
#endif
            current->bird.IsRinged, current->bird.Specie,
            current->bird.BirdAge, current->bird.HomeArea,
            current->bird.HomeHeight, current->bird.HomeFeederQuantity,
            current->bird.HomeHasNest, current->bird.Gender);
        current = current->next;
    }
    fclose(fp);
    return 0;
}

int
Import(Bird_t *head, char *filename)
{
    FILE *fp;

// NOTE/BUG: need to open for _reading_ and _not_ writing
#if 0
    if ((fp = fopen(filename, "wb")) == NULL) {
#else
    if ((fp = fopen(filename, "r")) == NULL) {
#endif
        perror("Error occurred while opening file");
        return 1;
    }
    Bird_t *current = head;

    while (current != NULL) {
        int items = fscanf(fp, "%d%s%d%d%d%d%d%s",
            &current->bird.IsRinged, current->bird.Specie,
            &current->bird.BirdAge, &current->bird.HomeArea,
            &current->bird.HomeHeight, &current->bird.HomeFeederQuantity,
            &current->bird.HomeHasNest, current->bird.Gender);
        dbgprt("Import: items=%d\n",items);
        if (items < 0)
            exit(1);
        current = current->next;

    }
    Print_Struct(head);
    fclose(fp);
    return 0;
}

void
Print_Single(Bird_t *current)
{
    printf("\nЧи окольцована птиця(1-так,0-ні):%d", current->bird.IsRinged);
    printf("\nНазва виду:%s", current->bird.Specie);
    printf("\nВік птаха:%d", current->bird.BirdAge);
    printf("\nПлоща домівки(у см:2):%d", current->bird.HomeArea);
    printf("\nВисота домівки(у см):%d", current->bird.HomeHeight);
    printf("\nКількість годівниць:%d", current->bird.HomeFeederQuantity);
    printf("\nЧи є гніздо(1-так,0-ні):%d", current->bird.HomeHasNest);
    printf("\nГендер:%s\n", current->bird.Gender);
}

int
Print_Struct(Bird_t *head)
{
    Bird_t *current = head;

// NOTE/BUG: this would segfault if we tried to print an empty list and would
// _not_ print the final list element
#if 0
    while (current->next != NULL) {
#else
    while (current != NULL) {
#endif
        Print_Single(current);
        printf("---------------------------------------\n");
        current = current->next;
    }
    printf("\n");
    return 0;
}

int
Get_element_by_pos(Bird_t *head, int pos)
{
    int originalpos = pos + 1;
    Bird_t *current = head;

    while (pos != 0) {
        current = current->next;
        pos--;
    }
    printf("\nОсь що ми найшли на %d позиції:", originalpos);
    if (current != NULL)
        Print_Single(current);
    return 0;
}

int
Add(Bird_t *head)
{
    Bird_t *current = head;
    Bird_t *new = Create(1);

// NOTE/BUG: this has to scan the list twice
#if 0
    int n = 0;
    while (current != NULL) {
        current = current->next;
        n++;
    }
    current = head;
    for (int i = 1; i < n; i++) {
        current = current->next;
    }
    current->next = new;
#else
    Bird_t *prev = NULL;
    for (;  current != NULL;  current = current->next)
        prev = current;
    prev->next = new;
#endif

    printf(" Елемент спиcку додано в кінець:\n\n");
    Print_Struct(head);

    return 0;
}

int
Del(Bird_t *head, int num)
{
    Bird_t *current = head;
    Bird_t *memory;

    for (int i = 0; i < num - 1; i++) {
        current = current->next;
        memory = current->next;
    }
    free(current);
    current = head;
    for (int i = 0; i < num - 2; i++) {
        current = current->next;
    }
    current->next = memory;
    Print_Struct(head);
    return 0;
}

int
regex_scan_element(char *dest_str, const char *pattern)
{
    /* Шаблон выражения */
    regex_t regex;

    /* Найденное выражение */
    regmatch_t regmatch;

    /* Код возврата */
    int r_code;

    /* Буфер ввода */
    char str[50];

    /* Считать строку из потока ввода */
#if 0
    scanf("%s", str);
#else
    fgets(str,sizeof(str),fin);
#endif
    str[strcspn(str, "\n")] = '\0';
    if (fin != stdin)
        printf("%s\n",str);

    /* Инициализация RegEx. Использовать расширенные выражения */
    r_code = regcomp(&regex, pattern, REG_EXTENDED);
    if (r_code != 0) {
        printf("function regcomp failed");
        return 1;
    }
    /* Сравнение строки с форматом */
    r_code = regexec(&regex, str, 1, &regmatch, 0);
    /* Если сравнение завершилось успешно */
    if (r_code == 0) {
        /* Копирование найденной строки в целевую строку */
        strncpy(dest_str, &str[regmatch.rm_so], regmatch.rm_eo - regmatch.rm_so);
        *(dest_str + (regmatch.rm_eo - regmatch.rm_so)) = '\0';

        regfree(&regex);
// NOTE/BUG: this won't even compile
#if 0
        return str;
#else
        return 0;
#endif
    }
    /* Если произошла ошибка */
    if (r_code != REG_NOMATCH) {
        printf("function regexec failed");
        regfree(&regex);
        return 2;
    }
    /* Если совпадений нет */
    regfree(&regex);
    return 1;
}
/**
 * @file main.c
 * @brief Файл с демонстрацией решения заданий из лабораторной работы №22
 *
 * @author Taradai S.V.
 * @version 1.0
 * @date 13-май-2021
 */

//#include "lib.c"

int
main(int argc,char **argv)
{
    char *filename = "birds.dat";
    Bird_t *head = NULL;

    --argc;
    ++argv;

    setlinebuf(stdout);

    if (argc > 0) {
        fin = fopen(argv[0],"r");
    }
    else {
        fin = stdin;
    }
    head = Create(3);

    printf("List:\n");
    Print_Struct(head);

    printf("Exporting ...\n");
    Export(head, filename);

    printf("Importing ...\n");
    Import(head, filename);

    printf("Imported list:\n");
    Print_Struct(head);

    printf("Get Element:\n");
    Get_element_by_pos(head, 2);

    printf("Add Element:\n");
    Add(head);

    if (fin != stdin)
        fclose(fin);

    return 0;
}
Craig Estey
  • 30,627
  • 4
  • 24
  • 48