The below code reads and stores the content of a .txt file into an array.
However instead of printing all the names in the file, it only prints the last line Matthew 789 30 times. My print function looks right but not sure where am I going wrong.
main
while (fscanf( in , "%s %s", name, num) == 2) {
array_of_students[i] = make_node(name, num);
}
printf("\nOriginal unsorted array\n");
print_array(array_of_students, 30);
Function:
Student * make_node(char * name, char * number) {
Student * new_student;
new_student = (Student * ) malloc(CLASS_SIZE * sizeof(Student));
int i = 0;
new_student[i].name = NULL;
new_student[i].number = NULL;
new_student[i].name = name;
new_student[i].number = number;
i++;
return new_student;
}
void print_array(Student * array_of_students[], int size) {
for (int i = 0; i < 30; i++) {
printf("%s %s\n", array_of_students[i] -> name, array_of_students[i] -> number);
}
}
txt file:
John 123
Walter 456
Matthew 789
You're assigning the same pointer values for name and number for each Student object you're creating, and overwriting the arrays those pointers point to each time.
You need to allocate space for the name and number members to point to space to store the strings in question and copy them over. You're also allocating space for too many Student objects. You only need one here:
Student *make_node(char * name, char * number) {
Student *new_student = malloc(sizeof(Student));
new_student->name = strdup(name);
new_student->number = strdup(number);
return new_student;
}
You also need to increment i in the scanf loop:
i = 0;
while (fscanf( in , "%s %s", name, num) == 2) {
array_of_students[i++] = make_node(name, num);
}
array_of_students[i] = make_node(name, num);
But nothing's incrementing i when you go around the loop. Should be i++?
print_array(array_of_students, 30);
Probably should pass i instead of 30.
for (int i = 0; i < 30; i++)
and you didn't use size here
Related
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct student{
int grade;
int enrollCode;
}student;
typedef struct colVoidStar{
int capacity;
int num_itens_curr;
void **arr;
int current_pos;
}colVoidStar;
colVoidStar *colCreate(int capacity){
if(capacity > 0){
colVoidStar *c = malloc(sizeof(colVoidStar));
if(c != NULL){
c->arr = (void**)malloc(sizeof(void*)*capacity);
if( c->arr != NULL){
c->num_itens_curr = 0;
c->capacity = capacity;
return c;
}
free(c->arr);
}
free(c);
}
return NULL;
}
int colInsert(colVoidStar *c, void *item){
if(c != NULL){
if(c->num_itens_curr < c->capacity){
c->arr[c->num_itens_curr] = (student*)item;
c->num_itens_curr++;
return 1;
}
}
return 0;
}
void *colRemove(colVoidStar *c, void *key, int compar1(void* a, void* b)){
int(*ptrCompar)(void*, void*) = compar1;
student* eleRemoved;
if(c != NULL){
if(c->num_itens_curr > 0){
int i = 0;
for(i; i < c->num_itens_curr; i++){
if(ptrCompar((void*)key, (void*)c->arr[i]) == 0){
eleRemoved = (student*)c->arr[i];
for(int j = i; j < c->num_itens_curr; j++){
c->arr[i] = c->arr[i + 1];
c->arr[i + 1] = 0;
}
return (void*)eleRemoved;
}
return NULL;
}
}
}
return NULL;
}
int compar1(void *a, void*b){
int key;
student *item;
key = *(int*)a;
item = (student*)b;
return (int)(key - item->enrollCode);
}
int main(){
int finishProgram = 0, choose, capacity, returnInsert, removeEnroll;
colVoidStar *c;
student *a, *studentRemoved;
while(finishProgram != 9){
printf("-----------------panel-----------------------\n");
printf("Type: \n");
printf("[1] to create a collection;\n");
printf("[2] to insert a student;\n");
printf("[3] to remove some student of collection;\n");
printf("--------------------------------------------------------\n");
scanf("%d", &choose);
switch(choose){
case 1:
printf("Type the maximum of students the collection will have: \n");
scanf("%d", &capacity);
c = (colVoidStar*)colCreate(capacity);
if(c == NULL){
printf("Error in create collection!\n");
}
break;
case 2:
if(c->num_itens_curr < capacity){
a = (student*)malloc(sizeof(student));
printf("%d student:(type the Grade and the Enroll code, back-to-back)\n", c->num_itens_curr + 1);
scanf("%d %d", &a->grade, &a->enrollCode);
returnInsert = colInsert(c, (void*)a);
if(returnInsert == 1){
for(int i = 0; i < c->num_itens_curr; i++){
printf("The student added has grade = %d e enrollCode = %d \n", (((student*)c->arr[i])->grade), ((student*)c->arr[i])->enrollCode);
}
}else{
printf("the student wasn't added in the collection\n");
}
}else{
printf("it's not possible to add more students to the colletion, since the limit of elements was reached!");
}
break;
case 3:
printf("Type an enrollcode to remove the student attached to it:\n");
scanf("%d", &removeEnroll);
studentRemoved = (student*)colRemove(c, &removeEnroll, compar1(&removeEnroll, c->arr[0]));
if(studentRemoved != NULL)
printf("the student removed has grade = %d and enrollcode %d.", studentRemoved->grade, studentRemoved->enrollCode);
else
printf("the number typed wasn't found");
break;
}
}
return 0;
}
---> As you can realize, what I'm trying to do, at least at this point, is access and remove an item(student* that initially will assume a void* type) of a student's collection(void** arr) using a sort of enrollment code. However, I'm having problems with Segmentation Fault and can't understand why and how can solve them, hence my question up there. Debugging the code I found out the errors lies at: if(ptrCompar((void)key, (void**)*c->arr[i]) == 0) inside of Remove function and return (int)(key - item->matricula) inside of Compar1.
Besides, if you can point me out some articles/documentations/whatever that helps me to understand how to cope with problems like that, I'll appreciate it a lot.
Here are the problems I see in colRemove:
(Not really a problem, just a matter of style) Although the function parameter int compar1(void* a, void* b) is OK, it is more conventional to use the syntax int (*compar1)(void* a, void* b).
(Not really a problem) Having both compar1 and ptrCompar pointing to the same function is redundant. It is probably better to name the parameter ptrCompar to avoid reader's confusion with the compar1 function defined elsewhere in the code.
The function is supposed to be general-purpose and shouldn't be using student* for the eleRemoved variable. Perhaps that was just for debugging? It should be void*.
After the element to be removed has been found, the remaining code is all wrong:
c->num_itens_curr has not been decremented to reduce the number of items.
The code is accessing c->arr[i] and c->arr[i + 1] instead of c->arr[j] and c->arr[j + 1].
c->arr[j + 1] may be accessing beyond the last element because the loop termination condition is off by 1. This may be because c->num_itens_curr was not decremented.
The assignment c->arr[j + 1] = 0; is not really needed because all but the last element will be overwritten on the next iteration, and the value of the old last element does not matter because the number of items should be reduced by 1.
(Not really a problem) There is unnecessary use of type cast operations in the function (e.g. casting void * to void *).
Here is a corrected and maybe improved version of the function (using fewer variables):
void *colRemove(colVoidStar *c, void *key, int (*ptrCompar)(void* a, void* b)){
void* eleRemoved = NULL;
if(c != NULL){
int i;
/* Look for item to be removed. */
for(i = 0; i < c->num_itens_curr; i++){
if(ptrCompar(key, c->arr[i]) == 0){
/* Found it. */
eleRemoved = c->arr[i];
c->num_itens_curr--; /* There is now one less item. */
break;
}
}
/* Close the gap. */
for(; i < c->num_itens_curr; i++){
c->arr[i] = c->arr[i + 1];
}
}
return eleRemoved;
}
In addition, this call of colRemove from main is incorrect:
studentRemoved = (student*)colRemove(c, &removeEnroll, compar1(&removeEnroll, c->arr[0]));
The final argument should be a pointer to the compar1 function, but the code is actually passing the result of a call to the compar1 function which is of type int. It should be changed to this:
studentRemoved = (student*)colRemove(c, &removeEnroll, compar1);
or, removing the unnecessary type cast of the the void* to student*:
studentRemoved = colRemove(c, &removeEnroll, compar1);
The colInsert function is also supposed to be general-purpose so should not use this inappropriate type cast to student*:
c->arr[c->num_itens_curr] = (student*)item;
Perhaps that was also for debugging purposes, but it should just be using item as-is:
c->arr[c->num_itens_curr] = item;
As pointed out by #chux in the comments on the question, the expression key - item->enrollCode in the return statement of compar1 may overflow. I recommend changing it to something like this:
return key < item->enroleCode ? -1 : key > item->enrolCode ? 1 : 0;
or changing it to use this sneaky trick:
return (key > item->enroleCode) - (key < item->enroleCode);
below I have posted my code. When I compile I receive no errors, and only one warning about variables I haven't used yet. the code works all the way to the line in code where it starts to print. I have tested all the sections and I believe that one is at fault. please let me know what I am doing wrong so I can fix it.
#include <stdio.h>
#include <string.h>
#define NUM_LINES 37
#define LINE_LENGTH 60
void select_sort_str(char list[NUM_LINES][LINE_LENGTH], int n);
int alpha_first(char list[NUM_LINES][LINE_LENGTH], int min_sub, int max_sub);
int main (void){
//store each line in an array of strings
FILE *inp;
FILE *outp;
char hurr[NUM_LINES][LINE_LENGTH];
;
inp = fopen("hurricanes.csv","r");
outp = fopen("out.txt","w");
//read in lines from file
for (int i = 0; i<NUM_LINES; i++){
fgets(hurr[i], LINE_LENGTH, inp);
}
inp = fopen("hurricanes.cvs","r");
//printf("%s", hurr[0]);
//define function
select_sort_str(hurr, NUM_LINES);
return(0);
}
int
alpha_first(char list[NUM_LINES][LINE_LENGTH], // input - array of pointers to strings
int min_sub, // input - min and max subscripts of
int max_sub) // portion of list to consider
{
int first, i;
first = min_sub;
for (i = min_sub + 1; i <= max_sub; ++i) {
if (strcmp(list[i], list[first]) < 0) {
first = i;
}
}
return (first);
}
/*
* Orders the pointers in an array list so they access strings in
* alphabetical order
* Pre: first n elements of list reference string of uniform case;
* n >= 0
*/
void
select_sort_str(char list[NUM_LINES][LINE_LENGTH], // input/output - array of pointers being
// ordered to acces strings alphabetically
int n) // input - number of elements to sort
{
int fill, // index of element to contain next string in order
index_of_min; // index of next string in order
char *temp;
char temp1[NUM_LINES][LINE_LENGTH];
for (fill = 0; fill < n - 1; ++fill) {
index_of_min = alpha_first(list, fill, n - 1);
if (index_of_min != fill) {
temp = list[index_of_min];
list[index_of_min][LINE_LENGTH] = list[fill][LINE_LENGTH];
strncpy(temp1[index_of_min], list[index_of_min], LINE_LENGTH);
temp1[fill][LINE_LENGTH] = *temp;
}
}
char *name;
char *cat = 0;
char *date;
for (int i = 0; i<NUM_LINES; i++){
name = strtok(NULL, ",");
cat = strtok(NULL, "h");
date = strtok(NULL, " ");
printf("%s %s %s\n", name, cat, date);
}
// for( int i =0; i<NUM_LINES; i++){
// printf("%s", list[i]);
// }
}
The only first parameter you ever pass to strtok is NULL. You never actually give it anything to parse. Did you perhaps mean strtok(temp1[i], ",");?
Also, why no error checking? It's much easier to find bugs in code with error checking.
Right now this function is deleting the last name given by the user from a list, but I need it to delete all the names that match the name given by the user, not just the first occurrence of the user input, and need to free up allocated memory of the names that got deleted. How can I do this?
int deleteR(char**Fname,char **Lname,float *score,int count)
{
int i=0,j=0;
char *Lastname;
printf("\n Enter the Last Name of the Student you would like to delete from the records. ");
Lastname = (char *)malloc(15 * sizeof(char));
printf("\nLast Name: ");
scanf("%s",Lastname);
int counter = count;
for(i=0;i<count-1;i++)
{
if(strcmp(Lname[i],Lastname)==0)
{
for(j=i;j<count;j++)
{
Lname[j]=Lname[j+1];
Fname[j]=Fname[j+1];
score[j]=score[j+1];
}
counter--;
}
}
count=counter;
return count;
}
In case your loop on j remove entries because you do not change count later in a loop on i you will access values already checked and may freed because removed
You also have a memory leak because you allocate memory for Lastname but you never free it, and in fact there is no reason to not have Lastname as an array in the stack. Also your scanf can write out of Lastname without limit in size.
You do not need to have two embedded loops as you do, only one is enough to move entries managing an index to write and an other to read :
int deleteR(char**Fname, char **Lname, float *score, int count)
{
char lastname[16];
printf("\nEnter the Last Name of the Student you would like to delete from the records: ");
if (scanf("%15s", lastname) == 1) {
int i;
/* that first loop to search if the lastname is present */
for (i = 0; i < count; ++i) {
if (!strcmp(Lname[i], lastname)) {
/* at least present one time, update lists */
int futureCount = count - 1;
int j;
/* it seems you want to free removed resources */
free(Lname[i]);
free(Fname[i]);
/* that loop to move useful elements */
for (j = i + 1; j < count; ++j) {
if (strcmp(Lname[j], lastname)) {
/* still usefull */
Lname[i] = Lname[j];
Fname[i] = Fname[j];
score[i] = score[j];
i += 1;
}
else {
/* useless */
/* it seems you want to free removed resources */
free(Lname[j]);
free(Fname[j]);
futureCount -= 1;
}
}
return futureCount;
}
}
}
else
puts("EOF");
return count;
}
Using that main function to check :
int main()
{
char * fname[5];
char * lname[5];
float score[5];
int count, i;
fname[0] = strdup("Wolfgang Amadeus");
lname[0] = strdup("Mozart");
score[0] = 0;
fname[1] = strdup("Johann Sebastian");
lname[1] = strdup("Bach");
score[1] = 1;
fname[2] = strdup("Leopold");
lname[2] = strdup("Mozart");
score[2] = 2;
fname[3] = strdup("Johann Christian");
lname[3] = strdup("Bach");
score[3] = 3;
fname[4] = strdup("Ludwig van");
lname[4] = strdup("Beethoven");
score[4] = 4;
count = deleteR(fname, lname, score, 5);
printf("new lists:\n");
for (i = 0; i != count; ++i)
printf("%s %s : %g\n", fname[i], lname[i], score[i]);
return 0;
}
Compilation and executions :
pi#raspberrypi:/tmp $ gcc -Wall d.c
pi#raspberrypi:/tmp $ ./a.out
Enter the Last Name of the Student you would like to delete from the records: Chopin
new lists:
Wolfgang Amadeus Mozart : 0
Johann Sebastian Bach : 1
Leopold Mozart : 2
Johann Christian Bach : 3
Ludwig van Beethoven : 4
pi#raspberrypi:/tmp $ ./a.out
Enter the Last Name of the Student you would like to delete from the records: Mozart
new lists:
Johann Sebastian Bach : 1
Johann Christian Bach : 3
Ludwig van Beethoven : 4
pi#raspberrypi:/tmp $
I have written this program where I can add pics to a staff using their names. but right now it adds the new value but the already existing values becomes 0.
this is the outcome:
type in the name you would like to add pic to
Anna
type in pic
55
1.Show existing
2.add pic to a staff
1
Adam 1,2,3,
Anna 0,0,0,55,
the rest of the code:
typedef struct Staff
{
char name[30];
int *pic;
int imagecount;
} Staff;
void printStaff(Staff *pStaff)
{
printf("%s ", pStaff->name);
if ( pStaff->pic) {
for(int i=0; i<pStaff->imagecount; i++){
printf("%d,",pStaff->pic[i]);
}
}
printf("\n");
}
void PrintList(Staff aLista[], int staffCount)
{
for (int i = 0; i < staffCount; i++) {
printStaff(&aLista[i]);
}
}
UPDATED CODE:
Staff addpic(Staff array[], int staffCount)
{
Staff newStaff = {};
printf("type in the name you would like to add pic to \n");
fgets(newStaff.name, 30, stdin);
for(int i = 0; i< staffCount; i++) {
if(strcmp(array[i].name,newStaff.name)==0) {
if(array[i].imagecount<5) {
printf("type in pic\n");
int newpic;
scanf("%d",&newpic);
array[i].imagecount++;
int *newpics = realloc(newStaff.pic, (array[i].imagecount) * sizeof(int));
newpics[array[i].imagecount-1] = newpic;
array[i].pic = newpics;
}
}
}
return newStaff;
the rest of the code:
int main(void)
{
int staffCount=0;
int input;
int test[3] = {1,2,3};
Staff myStaff[5] = { {"Adam", test, 3},{"Anna",test,3} };
staffCount=2;
do
{
printf("1.Show existing \n");
printf("2.add pic to a staff");
printf("\n");
scanf("%d", &input);
switch(input)
{
case 1:
PrintList(myStaff,staffCount);
break;
case 2:
addpic(myStaff,staffCount);
break;
default:
printf("inccorect inpput\n");
break;
}
}while (input<'1' ||input<'2');
return 0;
}
any help is appreciated, but I'm new to coding so keep that in mind.
In the addpic function you do
int *newpics = realloc(array[i].pic, ...);
One problem is that if you do it for one of the two elements you have initialized in array, then array[i].pic is pointing to the first element of an array (the array test in the main function).
Arrays can not be reallocated. If you want to reallocate the memory you need to allocate the original memory dynamically as well.
newStaff.pic is initialized to NULL and not updated then, so realloc(newStaff.pic, (array[i].imagecount) * sizeof(int)); is equivalent to malloc((array[i].imagecount) * sizeof(int));.
Elements allocated via malloc() and not initialized hae indeterminate value, and they happened to be zero in this case.
You can take over the contents by manually copying them.
int *newpics = realloc(newStaff.pic, (array[i].imagecount) * sizeof(int));
/* add this line to copy contents */
for (int j = 0; j < array[i].imagecount-1; j++) newpics[j] = array[i].img[j];
newpics[array[i].imagecount-1] = newpic;
Unfortunately, this method is not good because this may cause memory leak if addition like this to the same element of array is done multiple times.
Better way is to allocate the buffer to assign to img dynamically and pass them to realloc(). Then, realloc() will do the copying for you.
Initialization part:
int test[3] = {1,2,3};
Staff myStaff[5] = { {"Adam", test, 3},{"Anna",test,3} };
staffCount=2;
/* add this to change statically allocated arrays to dynamically allocated ones */
for (int i = 0; i < staffCOunt; i++) {
int* newpics = malloc(myStaff[i].imagecount * sizeof(int));
for (int j = 0; j < myStaff[i].imagecount; j++) newpics[j] = myStaff[i].img[j];
myStaff[i].img = newpics;
}
Updating part:
/* use array[i].pic instead of newStaff.pic */
int *newpics = realloc(array[i].pic, (array[i].imagecount) * sizeof(int));
/* then, no manual copying is required */
(error checkings are omitted)
First, I'll explain why I'm doing this the way that I am. I'm taking a course in computer programming and my professor has given us an assignment where we have to make an array of records(each contains a first name, last name, & score), and then allow the user to manipulate the records using menu options. All of this MUST be done using only pointer arrays, and structures are not allowed. I know it is a headache. I know it probably one of the most difficult ways to accomplish this, but its what the professor wants.
With that out of the way, below is what I have for my main function so far. most of the long printf functions are just me printing debugging information. Please take note of the declaration of the char*** variable. It is meant to function as a 3D array where nameRecords[0] would be the first record, nameRecords[0][0] would be the first name of the first record, and nameRecords[0][1] is the last name of the first record. The third dimension is nameRecords[0][0][21], as the strings are only meant to be 20 characters long plus null character.
int main(void)
{
char ***nameRecords = NULL;
float *scores = NULL;
int size = 0; // total number of records
int usrInt = 0;
while(usrInt < 1)
{
printf("\nEnter the number of records to record(min 1): ");
scanf("%d", &usrInt);
inpurge();
if(usrInt < 1) printf("\nMust be integer greater than 1.\n");
}
nameRecords = (char***)calloc((size), sizeof(char**));
scores = (float*)calloc(size, sizeof(float));
int i;
for(i = 0; i < usrInt; i++)
{
addRecord(&nameRecords, &scores, &size);
printf("\nnameRecords#%p :: nameRecords[%d]#%p :: nameRecords[%d][0]=%s :: nameRecords[%d][1]=%s\n", nameRecords, size - 1, nameRecords[size - 1], size - 1, nameRecords[size - 1][0], size - 1, nameRecords[size - 1][1]);
}
printf("\nnameRecords[0]#%p\n", nameRecords[0]);
prntRecords(nameRecords, scores, size);
printf("\n\n\n");
return 0;
}
The trouble comes after I pass, for the SECOND TIME, &nameRecords into the addRecord function, defined below. To clarify, the segmentation fault is not received if the user chooses to enter only 1 entry at the beginning of the main function, and the program actually runs and terminates as expected.
void addRecord(char ****records, float **scores, int *size)
{
printf("\t(*records)[0]%p\n", (*records)[0]);
++*size; // increment total number of records by 1
int index = (*size) - 1;
char ***tempNames = (char***)realloc(*records, (*size) * sizeof(char**)); // reallocate larger space.
if(tempNames != *records)
*records = tempNames; // set original pointer to new value.
printf("\n\tsize - 1 = %d\n", index);
float *tempScores = (float*)realloc(*scores, (*size) * sizeof(float)); // reallocate larger space.
if(tempScores != *scores)
*scores = tempScores; // set original pointer to new value.
printf("\ttempNames[0]#%p\n", tempNames[0]);
tempNames[index] = (char**)calloc(tempNames[index], 2 * sizeof(char*));
enterRecord(tempNames[index], scores[index]);
printf("\n\ttempNames#%p :: tempNames[0]#%p :: tempNames[%d][0]=%s :: tempNames[%d][1]=%s\n", tempNames, tempNames[0], index, tempNames[index][0], index, tempNames[index][1]);
printf("\n\t*records#%p :: *records[0]#%p :: *records[%d][0]=%s :: *records[%d][1]=%s\n", *records, (*records)[0], index, (*records)[index][0], index, (*records)[index][1]);
return;
}
Below is an example output of the program. Without taking too long to explain whats happening, the tabbed lines are the lines of output from within the addRecord function. Specifically, the pointer to the first record, record[0], has been turned into a garbage value on the second pass through the addRecord function, just after the enterRecord function.
Enter the number of records to record(min 5): 2
(*records)[0](nil)
size - 1 = 0
tempNames[0]#(nil)
Enter first name: 1
Enter last name: 1
Enter score: 1
COMPLETE enterRecord
tempNames#0x6387010 :: tempNames[0]#0x6387050 :: tempNames[0][0]=1 :: tempNames[0][1]=1
*records#0x6387010 :: *records[0]#0x6387050 :: *records[0][0]=1 :: *records[0][1]=1
nameRecords#0x6387010 :: nameRecords[0]#0x6387050 :: nameRecords[0][0]=1 :: nameRecords[0][1]=1
(*records)[0]0x6387050
size - 1 = 1
tempNames[0]#0x6387050
Enter first name: 2
Enter last name: 2
Enter score: 2
COMPLETE enterRecord
tempNames#0x6387010 :: tempNames[0]#0x40000000 :: tempNames[1][0]=2 :: tempNames[1][1]=2
*records#0x6387010 :: *records[0]#0x40000000 :: *records[1][0]=2 :: *records[1][1]=2
nameRecords#0x6387010 :: nameRecords[1]#0x63870b0 :: nameRecords[1][0]=2 :: nameRecords[1][1]=2
nameRecords[0]#0x40000000
records#0x6387010 :: records[0]#0x40000000
Segmentation fault
All of the debug information points to the enterRecord function as being the culprit. So here it is, the evil enterRecord function...
void enterRecord(char **names, float *score)
{
names[0] = (char*)calloc(21, sizeof(char)); // allocate first name string
names[1] = (char*)calloc(21, sizeof(char)); // allocate last name string
printf("\nEnter first name: ");
fgets(names[0], 21, stdin);
if(strlen(names[0]) == 20) // IGNORE. just handles overflow from fgets.
inpurge();
remNewLine(names[0]); // removes '\n' character at end of string
printf("\nEnter last name: ");
fgets(names[1], 21, stdin);
if(strlen(names[1]) == 20) // IGNORE. just handles overflow from fgets.
inpurge();
remNewLine(names[1]); // removes '\n' character at end of string
printf("\nEnter score: ");
scanf("%f", score);
inpurge();
printf("\nCOMPLETE enterRecord\n");
return;
}
Only... no attempt at altering the affected pointer was made. The pointer value to the second element of the records array(records[1]) was passed into the function, and nothing I can see is altering the value of the pointer of the first element of the records array(records[0]), though the value of records[0] is what's causing the segfault.
I am very sorry for the length and all obfuscatory code. Again, this seems like a terrible approach to writing this program, but its what the situation calls for. I just feel bad for the poor teacher's aide who has to grade 30+ of these assignments.
Any help is welcomed.
this problem seems to be better implemented as
#define MAX_FIRST_NAME_LEN (21)
#define MAX_LAST_NAME_LEN (21)
#define MAX_SCORES (10)
// in file global memory...
static char **ppFirstNames = NULL;
static char **ppLastName = NULL;
static int **ppScores = NULL;
static int numOfEntries = 0;
// in the record input function, which needs NO parameters
scanf ( "%d", &numOfEntries );
if scanf fails, exit
ppFirstNames = malloc (numOfEntries*sizeof char*);
if malloc fails, exit
memset (ppFirstName, '\0', numOfEntries*sizeof char* );
ppLastName = malloc (numOfEntries*sizeof char*);
if malloc fails, free all, exit
memset (ppLastName, '\0', numOfEntries*sizeof char* );
ppScores = malloc (numOfEntries *sizeof int* );
if malloc fails, free all, exit
for(int i=0; i<numOfEntries; i++ )
ppFirstNames[i] = malloc( MAX_FIRST_NAME_LEN );
if malloc fails free all, exit
memset ( ppFirstNames[i], '\0', MAX_FIRST_NAME_LEN );
ppLastName[i] = malloc (MAX_LAST_NAME_LEN);
if malloc fails free all, exit
memset ( ppLastName[i], '\0', MAX_LAST_NAME_LEN );
ppScores[i] = malloc (MAX_SCORES *sizeof int);-1
if malloc fails, free all, exit
memset (ppScores[i], '\0', MAX_SCORES *sizeof int );
end for
for ( int i=0; i < numOfEntries; i++ )
now read each record
scanf( "%(MAX_FIRST_NAME_LEN-1)s", ppFirstNames[i] );
if scanf fails, free all, exit
scanf( "%(MAX_LAST_NAME_LEN-1)s", ppLastNames[i] );
if scanf fails, free all exit
for( int j=0; j< MAX_SCORES; j++ )
now read this students scores
int tempScore;
scanf( "%d", tempScore );
if scanf fails, free all, exit
if -1 == tempScore ) break;
ppScores[i][j] = tempScore;
end for
end for
The above is the pseudo code for inputting the records
and should be enough to get the input correct.
printing the info thereafter should be easy.
Example to use realloc for array multidimensional:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int size_initial = 10;
int **ptr;
int i, j;
ptr = (int**) malloc(sizeof (int*) * size_initial);
for (i = 0; i < size_initial; i++) {
ptr[i] = (int*) malloc(sizeof (int) * 10);
for (j = 0; j < 10; j++)
ptr[i][j] = i+j;
}
/* realloc +10 */
ptr = (int**) realloc(ptr, sizeof (int*) * (size_initial * 2));
for (i = size_initial; i < size_initial * 2; i++) {
ptr[i] = (int*) malloc(sizeof (int) * 10);
for (j = 0; j < 10; j++) {
ptr[i][j] = i+j;
}
}
/* print values */
for (i = 0; i < 20; i++) {
for (j = 0; j < 10; j++) {
printf("ptr[%d][%d] = %d\n", i, j, ptr[i][j]);
}
}
return 0;
}