1

I am simply trying to get user input, store it in a struct, write it to a binary file, and then read it again. It is for the start of a contact book type program. When I try to retrieve the data for a single struct, it does not read into my readStruct and I get a seg fault at the marked comment in the code.

Also, please mind the messy use of dynamic strings and user input. I was just playing around and learning from it.

Thanks.

Heres the code:

int main(void) {

  struct contactStruct {
    int phoneNumber;
    char * firstName;
    char * lastName;
    char * companyName;
  };
  struct contactStruct contact;
  struct contactStruct read;

  //Variable Declaration
  int j = 1;
  char tempInput[100] = "-";
  char * menuInput;
  char * searchInput;
  bool menuLoop = false;
  FILE * filePointer;

  filePointer = fopen("contactList.db", "r+");
  if (filePointer == NULL) {
    filePointer = fopen("contactList.db", "w+");
  }

  printf("Welcome to the Contact Book Program\n");
  printf("This program will let you store and access all of your contacts!\n");
  do {
    menuLoop = false;
    printf("Would you like to: 'ADD', 'EDIT', 'VIEW', or 'REMOVE' a contact? - ");
    fgets(tempInput, sizeof(tempInput), stdin);
    for (int i = 0; i < strlen(tempInput); i++) {
      tempInput[i] = tolower(tempInput[i]);
    }
    menuInput = malloc(sizeof(char) * strlen(tempInput) + 1);
    strcpy(menuInput, tempInput);

    if (strcmp(menuInput, "add\n") == 0) {
      printf("Phone Number: ");
      fgets(tempInput, sizeof(tempInput), stdin);
      contact.phoneNumber = atoi(tempInput);

      printf("First Name: ");
      fgets(tempInput, sizeof(tempInput), stdin);
      contact.firstName = malloc(sizeof(char) * strlen(tempInput) + 1);
      strcpy(contact.firstName, tempInput);

      printf("Last Name: ");
      fgets(tempInput, sizeof(tempInput), stdin);
      contact.lastName = malloc(sizeof(char) * strlen(tempInput) + 1);
      strcpy(contact.lastName, tempInput);

      printf("Company Name: ");
      fgets(tempInput, sizeof(tempInput), stdin);
      contact.companyName = malloc(sizeof(char) * strlen(tempInput) + 1);
      strcpy(contact.companyName, tempInput);

      fwrite( & contact, sizeof(struct contactStruct), 1, filePointer);

    } else if (strcmp(menuInput, "view\n") == 0) {
      printf("Who are you searching for? (First Name): ");
      scanf("%s", tempInput);
      searchInput = malloc(sizeof(char) * strlen(tempInput) + 1);
      strcpy(searchInput, tempInput); // Get name being searched for

      fread( & read, sizeof(struct contactStruct), 1, filePointer);

      printf("DEBUG - File Pos: %ld Size of Struct: %lu\n", ftell(filePointer), sizeof(struct contactStruct));
      printf("Input: %s Searching: %s\n", searchInput, read.firstName); //Seg Fault Happens Here

      if (strcmp(searchInput, read.firstName) == 0) {
        printf("Here is the contact information given:\n\n");
        printf("%d %s %s %s \n", read.phoneNumber, read.firstName, read.lastName, read.companyName);
      } else {
        printf("Did not find\n");
      }
    } else {
      printf("Invalid Option, Try Again.\n");
      menuLoop = true;
    }
  }
  while (menuLoop == true);
  free(menuInput);
  free(searchInput);
  fclose(filePointer);

  return 0;
}
  • Writing a pointer is meaningless as a persistence. – BLUEPIXY Jun 25 '17 at 04:21
  • You are attempting to write and read pointers. Please create a character array with a defined size in the structure. – Grifplex Jun 25 '17 at 04:23
  • 1
    Yes, read the link @kaylum posted. Your code is working as you wrote it...you're writing memory locations to disk, not any string data...so you're reading memory locations from the file and then trying to access the data at those locations (which doesn't exist, and the locations are outside the program segments), which is why it segfaults. – Dale Jun 25 '17 at 04:38

1 Answers1

1

The problem is with your structure:

struct contactStruct 
{
    int phoneNumber;
    char * firstName;  // <--  you have pointers, not data
    char * lastName;
    char * companyName;
};

When you save your contactStruct to file, using fwrite( & contact, sizeof(struct contactStruct), 1, filePointer); you save the values of the pointers to the file, and not the contents of the strings they point to. This means the actual data never gets saved, and when you read the file, you have pointer that point nowhere.

If what you seek to do is simply have fixed-length records in your file - I suggest you do, for now, You should change your struture to hold data. The length. You must decide how long the strings should be depending on what you need.

#define CS_PHONE_LEN  11     // remember that your strings will need a zero termination.
#define CS_FIRSTNAME_LEN 24  // I've chosen arbitrary lengths for the demonstration.
#define CS_LASTNAME_LEN 24     
#define CS_COMPANY_LEN 24

struct contactStruct 
{
    char phoneNumber[CS_PHONE_LEN];    // phone numbers are usually stored as text. 
    char firstName[CS_FIRSTNAME_LEN];
    char lastName[CS_LASTNAME_LEN];
    char companyName[CS_COMPANY_LEN];
};

You will have to take care in your program not to store strings longer than the sizes defined in your structure, or the data will become corrupt. You'll probably want to use strncpy_s() to store strings in the data members, here's the doc for the function http://en.cppreference.com/w/c/string/byte/strncpy.

strncpy_s(cs.phoneNumber, CS_PHONE_LEN, userEntryString, CS_PHONE_LEN - 1);

If you use the older strncpy, beware that it will not null terminate your destination string if the source string is too long.

strncpy(cs.phoneNumber, userEntryString, CS_PHONE_LEN - 1);
cs.phoneNumber[CS_PHONE_LEN - 1] = 0;  // make sure it's null-terminated.

A safer, alternate way to write this (above is the more oft-used, 'classic' notation.

strncpy_s(cs.phoneNumber, sizeof(cs.phoneNumber), userEntryString, sizeof(cs.phoneNumber) - 1);

// or...

strncpy(cs.phoneNumber, userEntryString, sizeof(cs.phoneNumber) - 1);
cs.phoneNumber[sizeof(cs.phoneNumber) - 1] = 0;  // make sure it's null-terminated.

This way, your writes are independent of the name of the constants, while the lengths are always right.

Michaël Roy
  • 6,338
  • 1
  • 15
  • 19
  • Thank you for the response and solution. I understand my mistakes now, and will fix it using your suggestion. I appreciate the reasoning, as I am still learning. Thanks! –  Jun 25 '17 at 18:11
  • I forgot to post an alternate way, which is safest. Hold on... – Michaël Roy Jun 25 '17 at 18:12