|
 |
|
 |
03-23-2005, 09:58 PM
|
#1 (permalink)
|
|
Registered User
Join Date: Mar 2005
Posts: 7
|
File I/O and arrays
Having some difficulties with concept of moving strings from a file into an array in C.
The txt file my program is reading from looks like this:
Karen Smith 100 100 100 100 100
John Oliver 78 90 64 51
Henry Green 44 55 44 44
The goal is to read the first names and store in array, read last names store in a second array and then read the scores and store in a third array. The first two arrays are to have 50 columns and N rows. I created this code to just handle the first name array (fname) and to print the values of array on the screen so I can ensure that the array is taking in the proper values.
Code:
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
int N, i, j;
FILE *ifp, *ofp;
char **fname, **lname, *grades;
float **scores;
printf ("How many records do you have?\n");
scanf ("%d", &N);
ifp = fopen ("input.txt", "r");
if (ifp == 0)
{
printf ("\nNot able to open file!");
return 0;
}
else
for (i = 0; i < N; ++i)
for (j = 0; j <50; ++j)
fscanf (ifp, "%s", fname);
for (i = 0; i < N; ++i)
for (j = 0; j < 50; ++j)
printf ("%s", fname[i][j]);
printf ("\n");
return 0;
}
During runtime I get the following errors that occur after user is prompted to enter number of records.
0 [main] a 3000 handle_exceptions: Exception: STATUS_ACCESS_VIOLATION
6148 [main] a 3000 stackdump: Dumping stack trace to a.exe.stackdump
Very confused on whole topic of scanning characters from a file into an array. If anyone can comment on code or provide link for online info in general I would apreciate it.
Last edited by JaySun; 03-23-2005 at 09:59 PM.
Reason: Left out language
|
|
|
03-23-2005, 11:48 PM
|
#2 (permalink)
|
|
Newbie
Join Date: Jun 2002
Location: Denmark
Posts: 1,695
|
Code:
...
FILE *ifp, *ofp;
char **fname, **lname, *grades;
float **scores;
...
for (i = 0; i < N; ++i)
for (j = 0; j <50; ++j)
fscanf (ifp, "%s", fname);
for (i = 0; i < N; ++i)
for (j = 0; j < 50; ++j)
printf ("%s", fname[i][j]);
printf ("\n");
...
There are some flaws in this, you can't read into a char** without having allocated the needed memory, this will produce random behaviour from your program.
I'll work on a solution in a minut, I just gotta get some breakfast now.
|
|
|
03-24-2005, 12:31 AM
|
#3 (permalink)
|
|
Registered User
Join Date: Mar 2005
Posts: 7
|
When I started this program originally (I started all over again in frustration) I had set this up to deal with the array sizes.
Code:
fname = (char**) calloc (N, sizeof (char*));
for (i = 0; i < N; ++i)
fname[i] = (char*) calloc (50, sizeof (char));
lname = (char**) calloc (N, sizeof (char*));
for (i = 0; i < N; ++i)
lname[i] = (char*) calloc (50, sizeof (char));
scores = (float**) calloc (N, sizeof (float*));
for (i = 0; i < N; ++i)
scores[i] = (float*) calloc (4, sizeof (float));
grades = (char*) calloc (N, sizeof (char));
Does this look correct? Thanks for the help...Hope you enjoyed breakfast.
|
|
|
03-24-2005, 02:30 AM
|
#4 (permalink)
|
|
Newbie
Join Date: Jun 2002
Location: Denmark
Posts: 1,695
|
Yes, those alterations does some of the right things here, you're allocating the memory needed.
But what do you know about the scores ? aren't there supposed to be unlimited number of scores per person in the list ?
And where do the grades come from ?? I dont see any of that mentioned in your input.txt file...
Or are they something the teacher should type in, according to the output given by the program, when listing every student with theyre apropriate scores ?
But then, where should the program store that info ?
I have to attend a family easter dinner, but later tonight, when thats over, I'll have a working example ready.
|
|
|
03-24-2005, 09:20 AM
|
#5 (permalink)
|
|
Registered User
Join Date: Mar 2005
Posts: 7
|
The teacher is to enter each students name along with 4 scores for each student. Somewhere in the program it should take those 4 scores sum them up and divide by 4. Each number score is evaluated and assigned a letter grade (A = 90-100, B = 80-90, etc)....These letter grades are to be stored in array grades. In the end the program should print each students first and last name and letter grade on the screen. Then this is printed to file "output.txt". There is actualy a menu that the user will be prompted with :
1) Read student's records
2) Compute Greades
3) Display Grades
4) Store Grades
5) Quit
Sorry I have not mentioned this but I was mostly concerned with allocating the needed memory for each array, reading from the file and storing the data into the array. That should be the whole program in a nutshelll above.
|
|
|
03-24-2005, 03:02 PM
|
#6 (permalink)
|
|
Newbie
Join Date: Jun 2002
Location: Denmark
Posts: 1,695
|
Ok, I'm back, and I'm drunk.. So please take this with a grain of salt.
I've got a working example, it will read your input.txt file, and show you what it found in it.. I didn't oncorporate the desired functioanlity, but on teh other hand, this will take an unlimited number of students, with an unlimited number of grades per student.. What you decide to do with it si entirely up to you..
The code is base on a lot of pointer arritmetic, which at some points might seem obscure, but if you dont know what the h*** it is doing, then feel free to question that part, I might be sober nough tomorrow to even answer a qustion like that.. Or I might have fogotten why I did it in the first place...
Code:
#include <stdio.h> // printf(), fope(), fgets(), fclose()
#include <stdlib.h> // malloc(), free(), atoi()
#include <string.h> // strlen(), strncpy(), strtok()
#define NAME_LENGTH 64
#define LINE_LENGTH 1024
#define DELIMITER " \n"
/* The scores can be of any count */
typedef struct SCORES{
int score;
struct SCORES* prev;
struct SCORES* next;
}SCORES;
/* the names can be of any count */
typedef struct RECORDS{
char first_name[NAME_LENGTH +1];
char last_name[NAME_LENGTH +1];
SCORES* scores;
struct RECORDS* prev;
struct RECORDS* next;
}RECORDS;
int read_entries(FILE* fp, RECORDS* record, int verbose);
int free_me(RECORDS* record);
/* Run this sucker, instead of limiting the user to some uniq input.txt
* file, we give them the selection to parse that to teh program,
* aswell as a request for a verbose output, where they can follow
* what is happening during teh run of it all.
*/
int main(int argc, char** argv)
{
FILE* in_file;
/* record will be the initial record,
* the first one at all time
*/
RECORDS* record;
/* cur_record will be pointing to the
* curent used record at all times
*/
RECORDS* cur_record;
/* scores will be pointing to the current
* score assigned in the cur_record
*/
SCORES* scores;
int count_records, count_scores, verbose = 0;
/* we need to check if the program should be
* with verbose output or if it's just the file_name
* thats been passed to it.
*/
if(argc <= 1 || argc > 3)
{
printf("Usage: %s [-v] <filename>\n", argv[0]);
return -1;
}
/* The arguments given are indeed "-v" "filename" */
if(argv[1][0] == '-' && argc == 3)
{
verbose = 1;
if(!(in_file = fopen(argv[2], "r")))
{
printf("Unable to open file: %s\n", argv[2]);
return -1;
}
}
/* it was just a filename that was given */
else
if(!(in_file = fopen(argv[1], "r")))
{
printf("Unable to open file: %s\n", argv[2]);
return -1;
}
/* we allocate room for the very first read record */
record = (RECORDS*) malloc(sizeof(RECORDS));
record->prev = NULL;
record->next = NULL;
cur_record = record;
if(read_entries(in_file, cur_record, verbose))
{
printf("Error reading entries from file.\n");
free_me(record);
return -1;
}
fclose(in_file);
cur_record = record;
count_records = 1;
/* print what we've read */
while(cur_record)
{
count_scores = 1;
/* since it will allocate a NULL user, when theres an empty line
* we will have to correct that
*/
if(strlen(cur_record->first_name) <=1)
break;
printf("Summary for user [%.3d]: %s, %s\n", count_records, cur_record->last_name, cur_record->first_name);
scores = cur_record->scores;
while(scores)
{
/* since strtok() will give a NULL value, when dealing with EOL
* we will have to correct that
*/
if(!scores->score)
break;
printf(" \t %d%c", scores->score, ((count_scores % 4) ? ' ' : '\n'));
scores = scores->next;
count_scores++;
}
printf("\n");
count_records++;
cur_record = cur_record->next;
}
free_me(record);
return 0;
}
/* when reading everthing in the scores file, we need to dynamicaly
* allocate the memory needed from the heap.
* since we're allocating one instance at a time, theres a slight
* overkill in the allocation, but since the fgets() will consume much
* of the time spent here anyway, it's affordable.
*/
int read_entries(FILE* fp, RECORDS* record, int verbose)
{
RECORDS* cur_record;
RECORDS* next_record;
SCORES* cur_score;
SCORES* next_score;
char *str, buffer[LINE_LENGTH +1];
cur_record = (RECORDS*) malloc(sizeof(RECORDS));
if(!cur_record)
{
printf("Error allocating space on the heap for cur_record\n");
return 1;
}
cur_record->next = NULL;
cur_record->prev = NULL;
cur_record = record;
while(fgets(buffer, LINE_LENGTH, fp))
{ /* buffer should contain "first_name last_name score1 ... scoreN\n" */
/* any line should be longer than 2 chars */
if(strlen(buffer) < 2)
break;
if(verbose)
printf("Read line: %s\n", buffer);
/* first we strip the first_name and last_name */
strncpy(cur_record->first_name, strtok(buffer, DELIMITER), NAME_LENGTH);
if(verbose)
printf("Stored into first_name: %s\n", cur_record->first_name);
strncpy(cur_record->last_name, strtok(NULL, DELIMITER), NAME_LENGTH);
if(verbose)
printf("Stored into last_name: %s\n", cur_record->last_name );
/* then run through the rest, collecting all scores */
cur_score = (SCORES*) malloc(sizeof(SCORES));
if(!cur_score)
{
printf("Error allocating space on the heap for cur_score\n");
return 1;
}
cur_score->prev = NULL;
cur_score->next = NULL;
cur_record->scores = cur_score;
while(NULL != (str = strtok(NULL, DELIMITER)))
{
cur_score->score = atoi(str);
if(verbose)
printf("Stored into score: %d\n", cur_score->score);
next_score = (SCORES*) malloc(sizeof(SCORES));
if(!next_score)
{
printf("Error allocating space on the heap for next_score\n");
return 1;
}
next_score->prev = cur_score;
cur_score->next = next_score;
cur_score = next_score;
}
next_record = (RECORDS*) malloc(sizeof(RECORDS));
if(!next_record)
{
printf("Error allocating space on the heap for next_record\n");
return 1;
}
next_record->prev = cur_record;
cur_record->next = next_record;
cur_record = next_record;
}
return 0;
}
/* when dealing with malloc, a nice thing to do, is to
* free everything you've allocated, just to give back
* to the system what you've proclaimed
*/
int free_me(RECORDS* record)
{
RECORDS* cur_record;
SCORES* cur_score;
cur_record = record;
/* now work your way to the last record
* deleting everything that comes in your way
*/
while(cur_record)
{
cur_score = cur_record->scores;
while(cur_score)
{
if(!cur_score->next)
break;
cur_score = cur_score->next;
free(cur_score->prev);
}
if(!cur_record->next)
break;
cur_record = cur_record->next;
free(cur_record->prev);
}
return 0;
}
Boy I'm glad I wrote the explanations to the functions while I was still sober... Now It would have been filled with some extraordinarily remark, that wouldn't make any sence what so ever...
Sorry, but I'm too drunk to highlight any of this code, as I would normaly do, in order to point out the key terms and restricted variables, such as int, void, stdout, stdin, etc.
Last edited by redhead; 03-25-2005 at 12:34 AM.
Reason: Found a small flaw in the free_me() function
|
|
|
03-24-2005, 10:43 PM
|
#7 (permalink)
|
|
Registered User
Join Date: Mar 2005
Posts: 7
|
Thanks, drunky! I will look it over and let you know if I have any questions.
|
|
|
| Thread Tools |
|
|
| Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -8. The time now is 04:06 PM.
|
Copyright © 2000-2008, Milano Interactive
Web Hosting provided by Portal 360 Web Hosting
|
 |
|