c - 我的段错误

标签 c pointers segmentation-fault structure records

当我尝试向数据库添加记录时,我的代码出现问题。每次我在名字提示中输入超过几个字符的任何内容时,程序都会出现段错误,即使是在从旧记录中移动元素之后也是如此。我知道段错误是由于试图访问我们无法访问的内存而导致的,但我一生都无法弄清楚是什么原因造成的。这段代码的目的是创建一个信用卡类型的结构,该结构在头文件中定义,该结构具有一组硬编码的 4 条记录,并且能够打印当前数据库、添加记录、删除记录和其他选择从菜单中。现在我专注于添加和删除记录,因为它们是该程序中最困难的部分。为什么我在尝试添加记录时不断收到段错误错误?

头文件:

#ifndef myStruct
#define myStruct

struct creditCard
{
 char firstName[100];
 char lastName[100];
 char cardNumber[17]; //TA advised to use string since 16 digits will overflow in plain integer
 char expMonth[10];
};

//function headers below
int printCreditCard(struct creditCard *);

int sizeOfDb(struct creditCard *);

int countRecords(struct creditCard *);

int deleteRecord(struct creditCard *);

int addRecord(struct creditCard *);

#endif

这是实际的程序:

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

int accesses = 0; //number of times database was manipulated
int count = 0;  //used to count how many records there are; we always start at 4
//int size = 0; //used to tell us how big the database is
struct creditCard *ptr;  //chunk of memory for each record/structure
struct creditCard *headPtr; //chunk of memory for the first records/structure

int main(void)
{
    ptr = (struct creditCard *) malloc(4 * sizeof(struct creditCard));
    headPtr = ptr;

    memcpy(ptr->firstName,"Bob",100);
    memcpy(ptr->lastName,"Marley",100);
    memcpy(ptr->cardNumber,"0000000000000000",17);
    memcpy(ptr->expMonth,"September", 10);
    ptr++;
    count = count++;

    memcpy(ptr->firstName, "John", 100);
    memcpy(ptr->lastName, "Adams", 100);
    memcpy(ptr->cardNumber,"1111111111111111",17);
    memcpy(ptr->expMonth, "October", 10);
    ptr++;
    count = count++;

    memcpy(ptr->firstName, "Bill", 100);
    memcpy(ptr->lastName, "Gates", 100);
    memcpy(ptr->cardNumber,"2222222222222222",17);
    memcpy(ptr->expMonth, "January", 10);
    ptr++;
    count = count++;

    memcpy(ptr->firstName, "Steve", 100);
    memcpy(ptr->lastName, "Jobs", 100);
    memcpy(ptr->cardNumber,"3333333333333333",17);
    memcpy(ptr->expMonth, "May", 10);
    count = count++;

while (1)
{
//headPtr = ptr;  //put the newest database into headPtr so it points to the first record   in that database
//ptr = headPtr;  //start the database back at the first record
//countRecords(ptr); //update the count of the current database

    int sel;
    printf("MAIN MENU\n");
    printf("=====\n");
    printf("1.  Select 1 to print all records.\n");
    printf("2.  Select 2 to print number of records .\n");
    printf("3.  Select 3 to print size of database.\n");
    printf("4.  Select 4 to add record.\n");
    printf("5.  Select 5 to delete record.\n");
    printf("6.  Select 6 to print number of accesses to database.\n");
    printf("7.  Select 7 to Exit.\n");
    printf("Enter Your Selection:  \n");

    scanf("%d", &sel); //get user input;

    if (sel == 1)
    {
            printCreditCard(ptr);
            accesses++;
    }
    else if (sel == 2)
    {
            fprintf(stderr,"Number of records in the database is %d records\n", count); //pulls value of count from global updated variable
            accesses++;

    }
    else if (sel == 3)
    {
            sizeOfDb(ptr);
            accesses++;
    }
    else if (sel == 4)
    {
            ptr = headPtr;
            addRecord(ptr);
            accesses++;
    }
    else if (sel == 5)
    {
            deleteRecord(ptr);
            accesses++;
    }
    else if (sel == 6)
    {
            fprintf(stderr,"Number of accesses to the database is %d\n", accesses);
            accesses++;
    }
    else if (sel == 7)
    {
            printf("Now Exiting.\n");
            return 0;
    }
    else
    {
            printf("Invalid input, please select a valid option.\n");
            break; //go back to the main menu
    }
 }
}
//functions defined below
int sizeOfDb(struct creditCard *card2)
{
    int size = 0;
    int j;
    for (j = 1; j <= count; j++)
    {
            size += sizeof(card2->firstName); //get the size of each element
            size += sizeof(card2->lastName);
            size += sizeof(card2->cardNumber);
            size += sizeof(card2->expMonth);
            card2++;
    }
    //loop through each record and get sizeof() of each record
    fprintf(stderr, "Total Size of the Database is %d bytes.\n", size);
    return size;
}

int addRecord(struct creditCard *card3)
{
    count = count++;
    fprintf(stderr, "count is %d \n", count);
    int p;
    struct creditCard *tempStruct;
    //struct creditCard *dummy;
    char fName, lName, month, number;
    //tempStruct = (struct creditCard *) malloc (count * sizeof(struct creditCard)); //allocate   memory to a dummy record
    tempStruct = (struct creditCard *) malloc ((count+1) * sizeof(struct creditCard)); //allocate memory to a dummy record
    //dummy = (struct creditCard *) malloc (sizeof(struct creditCard));
    //dummy = (struct creditCard *) malloc (2 * sizeof(struct creditCard));
    card3 = headPtr; //start at the beginning of the old database
    for (p = 1; p < count; p++)     //copies the old database in the new database up to the record before the newly allocated record
    {
            memcpy(tempStruct->firstName, card3->firstName, 100);
            memcpy(tempStruct->lastName, card3->lastName, 100);
            memcpy(tempStruct->cardNumber, card3->cardNumber, 17);
            memcpy(tempStruct->expMonth, card3->expMonth, 10);
            fprintf(stderr, "first name is %s\n", tempStruct->firstName);
            if (p == count-1)
            {
                    tempStruct++;
            }
            else
            {
                    tempStruct++;
                    card3++;
            }
    }
    printf("Please enter your first name.\n");
    scanf("%s", &fName);
    fprintf(stderr, "fname is %s\n", &fName);
    memcpy(tempStruct->firstName, &fName, 100);//put first name in struct
    //memcpy(dummy->firstName, &fName,100);//put first name in struct
    fprintf(stderr, "struct name is %s\n", tempStruct->firstName);
    //fprintf(stderr, "dummy name is %s\n", dummy->firstName);
    printf("Please enter your last name.\n");
    scanf("%s", &lName);
    memcpy(tempStruct->firstName, &fName, 100);//put first name in struct
    //memcpy(dummy->lastName,&lName,100);//put last name in struct
    printf("Please enter your 16 digit credit card number with no spaces.\n");
    scanf("%s", &number);
    memcpy(tempStruct->firstName, &fName, 100);//put first name in struct
    //memcpy(dummy->cardNumber,&number,17);//put creditcard number in struct
    printf("Please enter the month in which your credit card expires.\n");
    scanf("%s", &month);
    memcpy(tempStruct->firstName, &fName, 100);//put first name in struct
    //memcpy(dummy->expMonth,&month, 10); //put month of expiration in struct

  //code below copies stuff from the dummy record to the new database called tempStruct
  //memcpy(tempStruct->firstName, dummy->firstName, 100);
 //memcpy(tempStruct->lastName, dummy->lastName, 100);
 //memcpy(tempStruct->cardNumber, dummy->cardNumber, 17);
 //memcpy(tempStruct->expMonth, dummy->expMonth, 10);

    card3 = tempStruct;  //put the new database in place of the old database
    //free(dummy); //clear memory for the dummy record because we don't need it anymore
    return 0;
 }

    int deleteRecord(struct creditCard *card4)  //goes to the last record in the database and clears the    memory for it, essentially deleting it
    {
    count = count--;
    int l;
    struct creditCard *newDb;  //will hold the new database with one less record at the end
    newDb = (struct creditCard *) malloc(count * sizeof(struct creditCard));

    for (l = 0; l < 4; l++)
    {
            memcpy(newDb->firstName,card4->firstName,100);
            memcpy(newDb->lastName,card4->lastName,100);
            memcpy(newDb->cardNumber,card4->cardNumber,17);
            memcpy(newDb->expMonth,card4->expMonth,10);
            card4++;
    }
    //now we need to put the data into the new record
    card4 = newDb;  //put the new database into ptr to hold as the new database
    return 0;
  }

 int printCreditCard(struct creditCard *card)
 {
  card = headPtr;  //start at the beginning of the database
  int i;
  if (count == 0)
  {
     printf("The database is empty\n");
     return 0;
  }
  else
  {
    for (i = 1; i <= count; i++)
    {
            printf("Credit Card Record %d\n", i);
            fprintf(stderr, "First Name = \%s\n", card-> firstName);
            fprintf(stderr, "Last Name = \%s\n", card-> lastName);
            fprintf(stderr, "Card Number = \%s\n", card-> cardNumber);
            fprintf(stderr, "Expiration Date = \%s\n\n", card-> expMonth);
            card++;  //go to the next record to print
    }
  }
  return 1; //we have now printed all records, go to main menu.
 }

最佳答案

这里确实有很多错误——你应该尝试使用 lint 或其他静态分析工具来帮助你发现错误。

一个特殊的问题 - 当你输入 fname 时,你正在向 scanf 传递一个指向单个字符的指针 - 你确实想向它传递一个指向字符数组的指针(实际上,你不想在所有,但我不会讨论这一点)。 Scanf 正在愉快地将输入字符复制到该单个字符之后的内存位置,这当然会在某些时候导致段错误。

您还需要学习使用某种调试器(gdb?),当出现段错误时,它将帮助您查看核心转储,以便您可以找到问题所在。

关于c - 我的段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26172799/

相关文章:

c - 顺序逐字节比较

c - C 函数示例

c - 将文本文件加载到二维数组中,然后与文字进行比较

c - 在 C 编程中,我试图使用指针反向打印我的数组,但我似乎无法得到它

c++ - Qt5 在关闭时崩溃

c - perl 中是否有与 read() 相反的函数,就像 C 中的 fwrite() 一样?

c - c中的int(*pt)[5]是什么意思

c++ - 为什么这个指针在其对象应该超出范围时有效? (以及其他一些奇怪的行为)

c - MPI_Scatter 段错误(信号 11)

c - Linux——内存映射文件