Reading text file into array of structures dynamic memory allocation

  • (2 Pages)
  • +
  • 1
  • 2

18 Replies - 11568 Views - Last Post: 23 July 2011 - 06:57 PM Rate Topic: -----

#1 riddinon24z  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 22
  • Joined: 22-July 11

Reading text file into array of structures dynamic memory allocation

Posted 22 July 2011 - 08:01 PM

I'm trying to do a simple program that will read data from a text file into an array of structures using dynamic memory allocation and then printing it. Here is the text file exactly as it was given to me:

Fred Flintstone 38 Male
Barney Rubble 36 Male
Wilma Flintstone 37 Female
Betty Rubble 36 Female
Pebbles Flintstone 4 Female
Bam-Bam Rubble 3 Male
Dino Flintstone 2 Male

IMPORTANT: There are 3 tabs (not spaces) before the numbers and 2 tabs after the numbers. I'm getting no errors or warnings, but my output box includes numbers that I do not want in there. I'm confused as to how to deal with the tabs. In the while loop, after the first fgets statement, the second argument is 19. And so, some of the strings that are read include the numbers from the text file as well. I've tried implementing the isdigit function to compensate for the tabs, but that doesn't affect the output of the numbers or the last string, at least due to the way I coded it. My best guess is that my main concern is reading the first string in the text file. Sorry if I wasn't really. This is my first time on here.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

int main(void)
{
    typedef struct
    {
        char* name;
        int* age;
        char* gender;
    }CHARACTER;

    CHARACTER* pChar;
    int charIndex;
    char temp[40];

    FILE* pData;

    if ((pData = fopen("lab4data.txt", "r"))==NULL)
    {
        printf("Error opening file.\n");
        return 100;
    }

    pChar = (CHARACTER*) calloc(7, sizeof(CHARACTER));

    charIndex = 0;
    while (charIndex<7)
    {
        fgets(temp, 19, pData);

        pChar[charIndex].name = (char*)calloc(strlen(temp) + 1, sizeof(char));
        strcpy(pChar[charIndex].name, temp);

        pChar[charIndex].age = (int*)malloc(sizeof(int));
        fscanf(pData, "%d", pChar[charIndex].age);

        fgets(temp, 10, pData);

        pChar[charIndex].gender = (char*)calloc(strlen(temp) + 1, sizeof(char));
        strcpy(pChar[charIndex].gender, temp);

        charIndex++;
    }

    for (charIndex=0; charIndex<7; charIndex++)
    {
        printf("%s %d%s", pChar[charIndex].name, *pChar[charIndex].age, pChar[charIndex].gender);
    }

    if (fclose(pData) == EOF )
	{
	printf("Error closing lab3data.txt\n");
	return 200;
	}

    return 0;
}



Is This A Good Question/Topic? 0
  • +

Replies To: Reading text file into array of structures dynamic memory allocation

#2 jimblumberg  Icon User is online

  • member icon


Reputation: 4013
  • View blog
  • Posts: 12,391
  • Joined: 25-December 09

Re: Reading text file into array of structures dynamic memory allocation

Posted 22 July 2011 - 09:18 PM

In the following line:
fgets(temp, 19, pData);



What happens if the name in the file is less than 19 characters?


When I change your print out routine to:
    for (charIndex=0; charIndex<7; charIndex++)
    {
       printf("%s\n", pChar[charIndex].name);
       // printf("%s %d%s", pChar[charIndex].name, *pChar[charIndex].age, pChar[charIndex].gender);
    }


I get this output:

Quote

Fred Flintstone 38
Barney Rubble 36 M
Wilma Flintstone 3
Betty Rubble 36 Fe
Pebbles Flintstone
Bam-Bam Rubble 3 M
Dino Flintstone 2


Jim

This post has been edited by jimblumberg: 22 July 2011 - 09:19 PM

Was This Post Helpful? 0
  • +
  • -

#3 riddinon24z  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 22
  • Joined: 22-July 11

Re: Reading text file into array of structures dynamic memory allocation

Posted 22 July 2011 - 09:59 PM

Interesting. When I put that in I get this:

Quote

Fred Flintstone
Barney Rubble 36
Wilma Flintstone
Betty Rubble 36
Pebbles Flintstone
Bam-Bam Rubble 3
Dino Flintstone


The reason I put 19 is because Pebbles Flinstone is the longest name on there. So 19 is the minimum characters it has to read to get all the names. However, because of that, it also gets the numbers for some of the lines with the shorter names like Barney Rubble.

This post has been edited by riddinon24z: 22 July 2011 - 10:00 PM

Was This Post Helpful? 0
  • +
  • -

#4 jimblumberg  Icon User is online

  • member icon


Reputation: 4013
  • View blog
  • Posts: 12,391
  • Joined: 25-December 09

Re: Reading text file into array of structures dynamic memory allocation

Posted 22 July 2011 - 10:18 PM

That is correct. You might want to use fgets() to retrieve the entire line from the file and then use sscanf() to parse the line. Since sscanf() stops processing C-strings when it encounters white space and since each name has a first and last name you could get the first name then the last name then age and then sex. Once you have the first and last names you could combine them with strcat() to store in your structure or have your structure store both the first and last names.


Jim
Was This Post Helpful? 0
  • +
  • -

#5 riddinon24z  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 22
  • Joined: 22-July 11

Re: Reading text file into array of structures dynamic memory allocation

Posted 22 July 2011 - 10:36 PM

Good idea, but how would I then dynamically allocate the memory of the two character strings as well as the integer for the age? I'd have to do that before I put the sscanf statement correct? If so, how would I do that if I'm going to use fgets for each entire line in the text file?

This post has been edited by riddinon24z: 22 July 2011 - 10:36 PM

Was This Post Helpful? 0
  • +
  • -

#6 jimblumberg  Icon User is online

  • member icon


Reputation: 4013
  • View blog
  • Posts: 12,391
  • Joined: 25-December 09

Re: Reading text file into array of structures dynamic memory allocation

Posted 22 July 2011 - 10:43 PM

Why all the dynamic memory? You are not using dynamic memory for the buffer now (char temp[40]; ) so maybe you will need another fixed size array or two?

I don't understand why age should be an array. It is a single value.

Jim

This post has been edited by jimblumberg: 22 July 2011 - 10:43 PM

Was This Post Helpful? 0
  • +
  • -

#7 riddinon24z  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 22
  • Joined: 22-July 11

Re: Reading text file into array of structures dynamic memory allocation

Posted 22 July 2011 - 10:47 PM

My mistake. I meant age as only an integer. I see what you're saying. Adding two more fixed arrays will help. I'll try it.
Was This Post Helpful? 0
  • +
  • -

#8 jimblumberg  Icon User is online

  • member icon


Reputation: 4013
  • View blog
  • Posts: 12,391
  • Joined: 25-December 09

Re: Reading text file into array of structures dynamic memory allocation

Posted 22 July 2011 - 10:53 PM

Age should be defined in your structure as int age;, Not as int *age;, there is no need for an array here.

Jim
Was This Post Helpful? 1
  • +
  • -

#9 riddinon24z  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 22
  • Joined: 22-July 11

Re: Reading text file into array of structures dynamic memory allocation

Posted 23 July 2011 - 12:33 AM

I got it to work. Sscanf really helped. Thank you. One last question: Does creating two more arrays of fixed length defeat the purpose of using dynamic memory allocation in a program like this one?
Was This Post Helpful? 0
  • +
  • -

#10 snoopy11  Icon User is offline

  • Engineering ● Software
  • member icon

Reputation: 768
  • View blog
  • Posts: 2,237
  • Joined: 20-March 10

Re: Reading text file into array of structures dynamic memory allocation

Posted 23 July 2011 - 03:28 AM

if you wanted to use dynamic memory in your program
you could do something like this


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

int main(void)
{
    typedef struct
    {
        char* name;
        char* age;
        char* gender;
    } CHARACTER;

    CHARACTER* pChar;
    int charIndex;
    char temp[60];
    char* pch;


    FILE* pData;

    if ((pData = fopen("lab4data.txt", "r"))==NULL)
    {
        printf("Error opening file.\n");
        return 100;
    }

    pChar = (CHARACTER*) calloc(8, sizeof(CHARACTER));

    charIndex = 0;
    while (charIndex<7)
    {
        fgets(temp, 45, pData);

        pch = strtok(temp,"\t");
        pChar[charIndex].name = (char*)malloc(sizeof(temp));
        pChar[charIndex].gender = (char*)malloc(sizeof(temp));
        pChar[charIndex].age = (char*)malloc(sizeof(temp));


        int counter =0;
        while (pch != NULL)
        {
            switch(counter)
            {
            case 0:
                strcpy(pChar[charIndex].name, pch);
                break;

            case 1:
                strcpy(pChar[charIndex].age, pch);
                break;
            case 2:
                strcpy(pChar[charIndex].gender, pch);
                break;
            }
            pch = strtok (NULL, "\t");

            counter++;
        }



        charIndex++;

    }

    for (charIndex=0; charIndex<7; charIndex++)
    {

        printf("%s %s %s", pChar[charIndex].name, pChar[charIndex].age, pChar[charIndex].gender);
    }


    free(pChar);

    if (fclose(pData) == EOF )
    {
        printf("Error closing lab3data.txt\n");
        return 200;
    }



    return 0;
}





It uses strtok to strip the tab delimiters
instead of sscanf...

Also dont forget to free up the memory allocated to pChar at the end.

This post has been edited by snoopy11: 23 July 2011 - 03:29 AM

Was This Post Helpful? 0
  • +
  • -

#11 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon

Reputation: 5800
  • View blog
  • Posts: 12,635
  • Joined: 16-October 07

Re: Reading text file into array of structures dynamic memory allocation

Posted 23 July 2011 - 06:51 AM

So many things coming up that are bad...

Don't cast your malloc or calloc. You don't need calloc. You certainly don't need a dynamically allocated int. It's unclear if you actually need a dynamically allocated anything. Use a function. Hell, use several functions. Don't put a struct in a function, even main. No magic numbers, use #define.

So, let's see these rules in practice.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAX_LINE_SIZE 60
#define MAX_LIST_SIZE 7

typedef struct {
	char *name;
	int age;
	char *gender; /* this should probably be one char or bool, but we'll go with this */
} CHARACTER;

void showList(CHARACTER* pChar, int size) {
	int charIndex;
	for (charIndex=0; charIndex<size; charIndex++) {
		printf("%s : %d : %s\n", pChar[charIndex].name, pChar[charIndex].age, pChar[charIndex].gender);
	}
	printf("\n");
}

char *dupString(const char *s) {
	char *dup = malloc(strlen(s) + 1);
	strcpy(dup, s);
	return dup;
}

int parseCharacter(const char *line, CHARACTER *c) {
	const int expectedResult = 4;
	int age;
	char first[MAX_LINE_SIZE], last[MAX_LINE_SIZE], gender[MAX_LINE_SIZE];
	
	if (sscanf(line, "%s %s %d %s", first, last, &age, gender)!=expectedResult) {
		printf("line invalid format\n");
		return 0;
	}
	strcat(first, " "); strcat(first, last);
	c->name = dupString(first);
	c->age = age;
	c->gender = dupString(gender);
	return 1;
}


int readFile(const char *filename, CHARACTER* pChar) {
	int linesRead = 0;
	FILE* pData;
	if (pData = fopen(filename, "r")) {
		int charIndex;
		for(charIndex = 0; charIndex<MAX_LIST_SIZE; charIndex++) {
			char temp[MAX_LINE_SIZE];
			fgets(temp, MAX_LINE_SIZE, pData);
			linesRead += parseCharacter(temp, &pChar[linesRead]);
		}
		fclose(pData);
	}
	return linesRead;
}


int main(void) {
	CHARACTER pChar[MAX_LIST_SIZE];
	int size = readFile("lab4data.txt", pChar);
	if (size==0) {
		printf("Error reading file.\n");
		return 1;
	} else {
		showList(pChar, size);
		return 0;
	}
}



Hope this helps.
Was This Post Helpful? 3
  • +
  • -

#12 snoopy11  Icon User is offline

  • Engineering ● Software
  • member icon

Reputation: 768
  • View blog
  • Posts: 2,237
  • Joined: 20-March 10

Re: Reading text file into array of structures dynamic memory allocation

Posted 23 July 2011 - 08:28 AM

Interesting I'll take all that on board Baavgai...

Slight issue I have tested this and my output is

line invalid format
Fred Flintstone 38 male
Barney Rubble 36 male
Wilma Flintstone 37 female
Betty Rubble 36 female
Pebbles Flintstone 4 female
Dino Flintsone 2 male

it seems not to like 'Bam Bam Rubble 3 male'
probably because the first name in Bam Bam is separated by whitespace
anyway round this problem..??

I do have to say I like your solution very much apart from this issue..

The solution I came up with can read 'Bam Bam Rubble 3 male'

but as always I bow to superior knowledge and in future wont use malloc in this way

Thanks again and I await your reply.

Oh can you explain why its bad to use malloc in this way... ?
that would be extra special too..

Best Wishes Snoopy.

This post has been edited by snoopy11: 23 July 2011 - 10:24 AM

Was This Post Helpful? 0
  • +
  • -

#13 jimblumberg  Icon User is online

  • member icon


Reputation: 4013
  • View blog
  • Posts: 12,391
  • Joined: 25-December 09

Re: Reading text file into array of structures dynamic memory allocation

Posted 23 July 2011 - 08:35 AM

Actually in the OP's file there is a dash ( - ) not a space in Bam-Bam.

Quote

Fred Flintstone 38 Male
Barney Rubble 36 Male
Wilma Flintstone 37 Female
Betty Rubble 36 Female
Pebbles Flintstone 4 Female
Bam-Bam Rubble 3 Male
Dino Flintstone 2 Male


Jim
Was This Post Helpful? 1
  • +
  • -

#14 snoopy11  Icon User is offline

  • Engineering ● Software
  • member icon

Reputation: 768
  • View blog
  • Posts: 2,237
  • Joined: 20-March 10

Re: Reading text file into array of structures dynamic memory allocation

Posted 23 July 2011 - 08:43 AM

Oh my mistake sorry Jim...

That would explain everything then

:bigsmile:

Thanks again

Best Wishes Snoopy.
Was This Post Helpful? 0
  • +
  • -

#15 riddinon24z  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 22
  • Joined: 22-July 11

Re: Reading text file into array of structures dynamic memory allocation

Posted 23 July 2011 - 12:08 PM

Baavgai, I think I understand what you're saying, but my assignment is to use dynamic memory for the two arrays and the int. I don't know whether or not that's a good idea. I'll agree that my code is nowhere near the most efficient it can be. I've had one course in C so far. I'm taking the second one now. Here's what I have:

typedef struct
    {
        char* name;
        int* age;
        char* gender;
    }CHARACTER;

void getData (FILE* pData, CHARACTER* pChar);
void printData (CHARACTER* pChar);
void threeToAge (CHARACTER* pChar);
void freeData (CHARACTER* pChar);

int main(void)
{

    CHARACTER* pChar;
    int charIndex;

    FILE* pData;

    if ((pData = fopen("lab4data.txt", "r"))==NULL)
    {
        printf("Error opening file.\n");
        return 100;
    }

    pChar = (CHARACTER*) calloc(7, sizeof(CHARACTER));

    getData (pData, pChar);

    printData (pChar);

    threeToAge (pChar);

    printf("\n3 Added to age:\n\n");
    printData (pChar);

    freeData (pChar);

    if (fclose(pData) == EOF )
	{
	printf("Error closing lab3data.txt\n");
	return 200;
	}

    return 0;
}

void getData(FILE* pData, CHARACTER* pChar)
{
    int charIndex;
    char temp1 [35];
    char temp2 [35];
    char temp3 [35];

    charIndex = 0;
    while (charIndex<7)
    {
        pChar[charIndex].age = (int*)malloc(sizeof(int));
        fgets(temp1, 80, pData);

        sscanf(temp1, "%19[^234678]%d %[^\n]", temp2, pChar[charIndex].age, temp3);

        pChar[charIndex].name = (char*)calloc(strlen(temp2) + 1, sizeof(char));
        strcpy(pChar[charIndex].name, temp2);

        pChar[charIndex].gender = (char*)calloc(strlen(temp3) + 1, sizeof(char));
        strcpy(pChar[charIndex].gender, temp3);

        charIndex++;
    }

    return;
}

void printData (CHARACTER* pChar)
{
    int charIndex;

    for (charIndex=0; charIndex<7; charIndex++)
    {
        printf("%s %d %s\n", pChar[charIndex].name, *pChar[charIndex].age, pChar[charIndex].gender);
    }

    return;
}

void threeToAge (CHARACTER* pChar)
{
    int charIndex;

    for (charIndex=0; charIndex<7; charIndex++)
    {
        *pChar[charIndex].age += 3;
    }


    return;
}

void freeData (CHARACTER* pChar)
{
    int charIndex;

    for (charIndex=0; charIndex<7; charIndex++)
    {
        free (pChar[charIndex].name);
        free (pChar[charIndex].age);
        free (pChar[charIndex].gender);
    }

    free (pChar);

    return;
}



This post has been edited by riddinon24z: 23 July 2011 - 12:14 PM

Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2