C程序在重新定位一个较大元素(2x)时崩溃



我是C语言的初学者,正在尝试以最简单的方式学习动态内存分配-我有一个管理学生记录的程序,我有一些问题,即使在谷歌搜索/堆叠流了好几个小时之后,我也无法解决这些问题-以下是这个程序要实现的目标:

  • 接收学生记录
  • 添加和删除记录(这些命令不起作用)
  • 对学生记录进行排序
  • 从这些记录中查找一些额外值

以下是在GDB调试器中发现的创建此错误的步骤(问题来自addRecord函数和freeMemory函数):

*** Error in `/home/a.out': realloc(): invalid next size: 
0x0000000000c42060 ***                                                        
Aborted 

当使用GCC编译并在GDB调试器之外运行时,它只会出错。

只有当我在程序中执行以下选项时才会发生这种情况:

1) 添加记录

2) 删除记录

3) 添加记录(然后崩溃)

1) 添加记录

2) 添加记录(然后崩溃)

我不确定是什么原因造成的,我也不知道如何解决,有人能帮助我朝着正确的方向前进吗?我曾尝试在freeMemory函数中的realloc成功后添加一个free,但没有成功,这会导致程序在删除添加的记录时崩溃。

这是代码:

#include <stdio.h>
#include <stdlib.h>
// Declare functions:
void printMenu();
void printRecords(char** fn, char** ln, float* s);
void addRecord(char** fn, char** ln, float* s);
void deleteRecord(char** fn, char** ln, float* s);
int freeMemory(char** fn, char** ln, float* s, char* n, int matches);
int findName(char** ln,char* n);

static int records; // global records variable
int main(){
int i, j;
int choice;
int option = -1;
printf("WELCOME TO THE STUDENT RECORD MANAGER 100 V 1.0! n");
printf("Please indicate the number of student records you want to enter (min 5, max 15): n");
scanf("%d",&records);
if(records < 5 || records > 15){
printf("You must enter more than five and less than 15... terminating. n");
return 0;
}
// Declare arrays
char** firstNames;
char** lastNames;
float* scores;
// Declare variables
char* search = malloc(64);
firstNames  =   malloc(records*sizeof(*firstNames));
lastNames   =   malloc(records*sizeof(*lastNames));
scores      =   malloc(records*sizeof(float));

printf("Please enter the records now (ex. firstName lastName score ENTER):n");
// Gather Records
for(i = 0; i < records; i ++){
printf("%d ",i+1);
firstNames[i] = malloc(254 * sizeof(char));
lastNames[i] = malloc(254 * sizeof(char));
//scores[i] = malloc(sizeof(float));
scanf("%s %s %f",firstNames[i], lastNames[i], &scores[i]);
}
// Generate menu and do actions
do{
printMenu();
scanf("%d",&choice);
switch(choice){
case 1:
printRecords(firstNames, lastNames, scores);
break;
case 2:
addRecord(firstNames, lastNames, scores);
break;
case 3:
deleteRecord(firstNames, lastNames, scores);
break;
case 0:
return 0;
}
}
while(1);
return 0;
}
// Print user menu
void printMenu(){
printf("tMain Menutn"
"============================n"
" > Print records (press 1) n"
" > Add a new record (press 2) n"
" > Delete a record (press 3) n"
" > Exit the program (press 0)n"
"============================n"
"Please select an option: ");
}
// Print all user records
void printRecords(char** fn, char** ln, float* s){
int i;
printf("THERE ARE %d RECORDS n",records);
for(i=0;i<records;i++)
printf("(%d) First name: %s | Last name: %s | Score: %0.2f n",i,fn[i],ln[i],s[i]); // will start at the first item and go i amount in the index
}
// Add user record
void addRecord(char** fn, char**ln, float* s){
char** tempPtr;
float* tempFPtr;
printf("Please input the values that you'd like to add (ex. firstName lastName score ENTER): n");
if(records+1 < 15){ // if the array is not larger than maximum value when we make it larger
// lets reallocate the arrays
tempPtr = realloc(fn, (records+1)*sizeof(*fn));
if(tempPtr){
printf("ALLOCATION successfully");
fn = tempPtr;
}
else{
printf("FAILED");
// Realloc Failed
}
tempPtr = realloc(ln, (records+1)*sizeof(*ln));
if(tempPtr){
printf("ALLOCATION successfully");
ln = tempPtr;
}
else{
printf("FAILED");
// Realloc Failed
}
/*tempFPtr = realloc(s, records+1*sizeof(float));
if(tempFPtr){
s = tempFPtr;
}*/
printf("There are now %d items.. n", records);
fn[records] = malloc(64); // in the LAST value of all arrays
ln[records] = malloc(64);
scanf("%s %s %f",fn[records], ln[records], &s[records]);
printf("(%d) > ADDED -> First name: %s | Last name: %s | Score: %0.2f n",records,fn[records],ln[records],s[records]);
int i;
records++; // increment by one
printf("There are now %d items.. n", records);
printf(" > Record successfully added.n");
}
else{
printf(" > You have hit the max amount of records allowed for this program (15).n");
}
}
// Delete all instances of user record by (last Name)
void deleteRecord(char** fn, char**ln, float* s){
char* lastName = malloc(32 * sizeof(char*));
printf("What is the last name of the student you would like to delete? n");
scanf("%s", lastName);
// searching for that record
int matches = findName(ln, lastName);
if(matches && records-matches > 4){ // this means it doesn't go below minimum 5
if(freeMemory(fn, ln, s, lastName, matches)){
printf(" > Record successfully deleted.n");
free(lastName);
}
}
else{
printf(" > Either no matches were found or deleting this value would put the number of records at less than 5. n");
}
}
// Extension of deleteRecord that does duplication to push 'delete' lastName to the end, then reallocates array to cut it off the end
int freeMemory(char** fn, char** ln, float* s, char* n, int matches){
int i,j;
/* LOGIC:
- REALLOCATE ARRAY BY X LESS SIZE AFTER PUSHING THE VALUES TO BE REMOVED TO THE END
- NEED TO DO THIS FOR THREE ARRAYS
- TO REMOVE:
- RUN THROUGH X AMOUNT OF TIMES PUSHING EACH SPECIFIC REMOVAL VALUE (IE) 1st found match
- TO THE END
SHIFT
- FOUND 1st MATCH
- MATCH = MATCH + 1
- MATCH + ! = MATCH + 2
- ETC UNTIL YOU HAVE A DUPLICATE AT THE END, THEN REALLOCATE BY 1 LESS
*/
char** tempPtr = NULL;
float* tempFPtr = NULL;
for(i=0;i<matches;i++){ // gonna go through as many times as matches
int match = 0;
// let's make sure the name isn't on the end of the array before we do all this junk
if(strcmp(n,*(ln+records-1)) == 0){
printf("FN");
tempPtr = realloc(fn, (records-1)*sizeof(*fn));
if(tempPtr){
fn = tempPtr;
printf("FN PASSED");
//free(fn[records]);
}
else{
// Realloc Failed
printf("FN FAILED");
}
printf("LN");
tempPtr = realloc(ln, (records-1)*sizeof(*ln));
if(tempPtr){
ln = tempPtr;
printf("LN PASSED");
//free(ln[records]);
}
else{
printf("LN FAILED");
// Realloc Failed
}
records--;
}
else{
// lets find the first match by going through each last name
for(j=0;j<records-1;j++){
// Lets find first match
if(strcmp(n,ln[j]) == 0){ // accessing index
// lets start copying
*(ln+j) = *(ln+j+1);
*(fn+j) = *(fn+j+1);
*(s+j)  = *(s+j+1);
match = 1;
}
else if(match){
// already copied first val so lets start copying the rest until we get to the end.
*(ln+j) = *(ln+j+1);
*(fn+j) = *(fn+j+1);
*(s+j)  = *(s+j+1);
}
}
printf("FN");
tempPtr = realloc(fn, (records-1)*sizeof(*fn));
if(tempPtr){
fn = tempPtr;
printf("FN PASSED");
//free(fn[records]);
}
else{
// Realloc Failed
printf("FN FAILED");
}
printf("LN");
tempPtr = realloc(ln, (records-1)*sizeof(*ln));
if(tempPtr){
ln = tempPtr;
printf("LN PASSED");
//free(ln[records]);
}
else{
printf("LN FAILED");
// Realloc Failed
}
/*tempFPtr = realloc(s, records-1*sizeof(float));
if(tempFPtr){
s = tempFPtr;
printf("S PASSED");
}
else{
printf("s FAILED ");
}*/
records--;
match = 0;
}
}
return 1;
}
// Finds how many instances of a last name are present
int findName(char** ln,char* n){
int i, counter=0;
for(i=0;i<records-1;i++){
if(strcmp(n,*(ln+i)) == 0){
counter++;
}
}
return counter;
}

错误出现在函数addRecord中。你有表达

tempPtr = safe_trim(ln, records+1*sizeof(*ln));

由于C运算符的优先级,它给出了records + (sizeof (*ln))的大小。乘法先于加法。该行应更改为:

tempPtr = safe_trim(ln, (records + 1) * sizeof(*ln));

此外,由于safe_trim总是返回一个有效的指针,无论是原始指针还是调整大小的指针,因此检查

tempPtr = safe_trim(fn, records+1*sizeof(*fn));
if(tempPtr){
printf("ALLOCATION successfully");
fn = tempPtr;
}
else{
printf("FAILED");
// Realloc Failed
}

永远不会跟随else分支,也不会处理分配失败。用realloc替换对safe_trim的调用不会对程序产生任何影响,除非允许检测分配失败。

我已经解决了这个问题。这是因为我没有使用三重指针,它没有寻址原始变量。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void printMenu();
void printRecords(char** fn, char** ln, double* s);
void addRecord(char ***fn, char ***ln, double **s);
void addString(char ***strArray, char* str);
void addDouble(double** dubArray, double dub);
void deleteRecord(char*** fn, char*** ln, double** s);
void removeString(char ***strArray);
void removeDouble(double** dubArray);
int findName(char** ln,char* n);
int records;
int counter;
int main(){
records = 0;
counter = 1;
int initRecords = 0;
int choice,i;
char **fn; // first Names
char **ln; // last Names
double *s; // score
printf("=  =n"
"Please enter how many value"
"s you would like to initall"
"y enter [min 5, max 15]: ");
scanf("%d", &initRecords);
if(initRecords < 5 || initRecords > 15)
return 0;
// allocate memory
fn = malloc(0); // will reallocate later
ln = malloc(0);
s =  malloc(0);
printf("Please enter the value (firstName lastName score ENTER): n");
for(i = 0;i<(initRecords);i++){
addRecord(&fn, &ln, &s);
counter++;
}
printf("Records added... n");
do{
printMenu();
scanf("%d",&choice);
switch(choice){
case 1:
printRecords(fn, ln, s);
break;
case 2:
addRecord(&fn,&ln,&s);
printf("> Record added. n");
break;
case 3:
deleteRecord(&fn, &ln, &s);
printf("> Record deleted. n");
break;
case 0:
return 0;
default:
return 0;
}
}
while(1);
}
// Print user menu
void printMenu(){
printf("tMain Menutn"
"============================n"
" > Print records (press 1) n"
" > Add a new record (press 2) n"
" > Delete a record (press 3) n"
"============================n"
"Please select an option: ");
}
// Print all user records
void printRecords(char** fn, char** ln, double* s){
int i;
for(i=0;i<records;i++)
printf("(%d) First name: %s | Last name: %s | Score: %0.2lf n",i+1,fn[i],ln[i],s[i]); // will start at the first item and go i amount in the index
}

void addRecord(char*** fn, char*** ln, double** s){
// gather value
char* fname = malloc(64);
char* lname = malloc(64);
double score;
records++;
printf("%d) ", (counter));
scanf("%s %s %lf",fname, lname, &score);
addString(fn, fname);
addString(ln, fname);
addDouble(s, score);
}
void addString(char*** strArray, char* str){
// realloc array one larger
*strArray = realloc(*strArray, (records) * sizeof(char*));
// set pointer equal
(*strArray)[records-1] = str;
}
void addDouble(double** dubArray, double dub){
// realloc array one larger
*dubArray = realloc(*dubArray, (records) * sizeof(double));
// set pointer equal
(*dubArray)[records-1] = dub;
}
void deleteRecord(char*** fn, char*** ln, double** s){
//This part gets the name
int i, j;
char *name = malloc(64);
printf("Please enter the last name of the record(s) you'd like to delete: ");
scanf("%s",name);
while(findName(*ln, name) != 0){
for(i = 0;i<records && strcmp(name,(*ln)[i]) != 0;i++);
records--;
//free((*ln)[i]);
//free((*fn)[i]);
for(i=i; i < records-1; i++){
(*ln)[i] = (*ln)[i+1];
(*fn)[i] = (*fn)[i+1];
(*s)[i] = (*s)[i+1];
}
removeString(fn);
removeString(ln);
removeDouble(s);
}
}
void removeString(char ***strArray){
*strArray = realloc(*strArray, (records) * sizeof(char*));
}
void removeDouble(double** dubArray){
*dubArray = realloc(*dubArray, (records) * sizeof(double));
}
// Finds how many instances of a last name are present
int findName(char** ln,char* n){
int i, counter=0;
for(i=0;i<records-1;i++){
if(strcmp(n,*(ln+i)) == 0){
counter++;
}
}
return counter;
}

相关内容

最新更新