我是C的初学者,我正在尝试以最简单的方式学习动态内存分配 - 我有一个管理学生记录的程序,我有一些问题,我不能在我的生活中弄明白甚至以后googleing / stackoverflowing的小时和小时 - 这是该程序要完成的任务:
以下是在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 Menu\t\n"
"============================\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;
}
答案 0 :(得分:4)
错误似乎出现在您的函数addRecord
中。你有表达式
tempPtr = safe_trim(ln, records+1*sizeof(*ln));
由于C operator precedence,其大小为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
分支,也不会处理分配失败。使用safe_trim
替换realloc
的呼叫不应对程序产生任何影响,除非允许检测分配失败。
答案 1 :(得分:0)
我已经解决了这个问题。这是因为我没有使用三重指针,因为它没有解决原始变量。
#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 Menu\t\n"
"============================\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;
}