Thread: help with structs and malloc!

  1. #16
    Registered User
    Join Date
    Sep 2009
    Posts
    16
    I think something in my printTable() is messing it up:

    Code:
    void printTable (struct table * symbols, FILE * out) {
        struct entry *n = symbols->first;
        printf("%s\n", symbols->first->symbol);
        printf("%s\n", n->symbol);
        //line above prints %s and then a newline
    
    	while (n != NULL) {
        	printf("%s", n->symbol);
            //this line prints a newline even though I didn't give it anything
        	printf("after");
        	printf("%d\t", n->linedef);
    
        	struct lineNode *nline = n->occur;
    
        	while ((nline != NULL) && (nline->lineoccur != -1)) {
        		printf("%d\t", nline->lineoccur);
        		nline = nline->next;
        	}
        	printf("\n");
    
        	fprintf(out, "%s\t", n->symbol);
        	fprintf(out, "%d\t\n", n->linedef);
        	n = n->next;
        }
    
    	printf("finished printing \n");
    }

    In tabletest.c I am using a nextWord function to get the next word and add to table:
    Code:
    int nextWord (char *str, int pos, char *word, int linecount, struct table *p) {
    
    	printf("string is %s\n", str);
    	if (emptyLine(str)== -1) {
    		printf("empty line\n");
    		return -1;
    	}
    
    
        int i=0;
    
        while (1) {
    	      if (*str == '\n' || *str == '\0' || *str == '#')
                   return -1;
              else if (i == pos) {
    	           break;
              }
    	      else {
    	           i++;
    	           str++;
              }
        }
        printf("str is now %s\n", str);
        int r = pos;
    
        char* word2 = word;
        int j;
        for (j=0; *str!='\n' || *str!=EOF; str++) {
    	    if (*str != ' ') {
    	        char c = *str;
    	        while (c != '\n' && c != ' ' && c!='\0') {
    		          r++;
    		          *word = c;
    		          word++;
    		          str++;
    		          c = *str;
                }
    	        *word = '\0';
    	        printf("word is %s\n", word2);
    
    	        char last = *--word;
    	        //fprintf(output, "%c \n", last);
                if (last != ':') {
                   printf("adding use\n");
                   addUse(word2, linecount, p);
                   printTable(p, output);
    	           return r;
                }
                else {
                	printf("adding def\n");
                	addDef(word2, linecount, p);
                	printTable(p, output);
                	return r;
                }
    	       printf("here %s  %d\n", word2, linecount);
                break;
    	    }
    	    else {
    	        r++;
                j++;
    	    }
        }
        word = word2;
        return r;
    }
    my main is just looping and reading one line in the input file, "abc"
    Code:
    main() {
    
    	printf("stack trace 1\n");
    	input = fopen("table.test", "r");
    	output = fopen("table.out", "w");
    
    	char *s;
    	int linecount = 1;
    	int pos;
    	char line[MAXLINE];
    	char word[MAXSYMBOL];
    	struct table *p = newTable();
    
    	printf("stack trace 1\n");
    
    
    	//processLine(s, 1, p);
    	//printTable(p, output);
    
    	/*while (s = newLine(input)) {
    		printf("reading input: %s\n", s);
    		processLine(s, linecount);
    		linecount++;
    	}*/
    
    
    	while (s = newLine(input)) {
    		printf("reading input: %s\n", s);
    		pos = 0;
    		while (1) {
    			printf("should go in here\n");
    			if ((pos = nextWord (s, pos, word, linecount, p)) == -1)
    				break;
    			printf("pos is %d\n", pos);
    			printTable(p, output);
    		}
    		linecount++;
    	}
    Is there any reason why printTable would print out a newline and mess up the formatting?

    stack trace 1
    stack trace 1
    reading input: abc
    should go in here
    string is abc
    line[i] is a
    should not be empty
    str is now abc
    word is abc
    adding use
    starting to add abc
    lineNum is 1
    going here
    added word abc
    finished adding use
    abc <--ok
    abc <--ok
    abc <--newline??
    after-1 1
    finished printing
    pos is 4
    abc
    abc
    abc
    after-1 1
    finished printing
    should go in here
    string is abc
    line[i] is a
    should not be empty
    reading input:
    should go in here
    string is
    line[i] is

  2. #17
    Registered User
    Join Date
    Sep 2009
    Posts
    16
    ok so I'm starting over and combining some code I wrote before:

    processLines.c (has main)
    Code:
    #include <stdio.h>
    #include <ctype.h>
    #include "table.h"
    #define MAXLINELEN 100
    #define MAXWORDLEN 20
    FILE *input, *output;
    
    int nextWord (char *, int, char *, int, struct table *p);
    int getline(char s[], char l[], int max);
    int getline2(char *, int max);
    void processLine(char pline, char line);
    int emptyLine (char line[]);
    
    int main ( ) {
    	char line[MAXLINELEN];
    	char pline[MAXLINELEN];
    	char word[MAXWORDLEN];
    	int pos;
    
        input = fopen("table.test", "r");
    	output = fopen("table.out", "w");
    
    
    	struct table *p = newTable();
        int linecount = 1;
    	
    	while (getline (line, pline, MAXLINELEN-1)) {
            if (emptyLine(line) != -1) {
    		   pos = 0;
               while (1) {
                     if ((pos = nextWord (line, pos, word, linecount, p)) == -1) {
    //here is where it loops and prints weird
                        printTable(p, output);
                        break;
                     }
               }
               linecount++;
            }
        }
    	printTable(p, output);
            fclose(input);
    	fclose(output);
    	return 0;
    }
    
    int emptyLine (char line[]) {
        int i=0;    
        while (1) {
              
              if (line[i] == '\0' || line[i] == '\n') {
                 return -1;
              }
              else if (line[i] != ' ') {
                   return i;
              }
              else {
                   i++;
              }    
        }
    }
    
    
    
    int nextWord (char *str, int pos, char *word, int linecount, struct table *p) {
    
        int i=0; 
        //fprintf(output, "pos is %d\n", pos);
        while (1) {
    	      if (*str == '\n' || *str == '\0' || *str == '#')
                   return -1;
              else if (i == pos) {
    	           break;
              }
    	      else {
    	           i++;
    	           str++;
              }
        }
        //fprintf(output, "str is now %s\n", str);
        int r = pos;
    
        char* word2 = word;
        int j;
        for (j=0; *str!='\n' || *str!=EOF; str++) {
    	    if (*str != ' ') {
    	        char c = *str;
    	        while (c != '\n' && c != ' ') {
    		          r++;
    		          *word = c;
    		          word++;
    		          str++;
    		          c = *str;
                }
    	        *word = '\0';
    	        
    	        char last = *--word;
                if (last != ':') {
                   addUse(word2, linecount, p);
                   here is where I'm calling the functions from table.c
    	           return r;
                }
                else {
                	addDef(word2, linecount, p);
                }
    	        //fprintf(output, "%s  %d\n", word2, linecount);
                break;
    	    }
    	    else {
    	        r++;
                j++;
    	    }
        }    
        word = word2;
        if (emptyLine(word) != -1)
           printf("%s\t%d\n", word, linecount);
        return r;
    }
    
    int getline(char s[], char l[], int lim) {
    
        int c, i=0;
        while (--lim>0 && (c=getc(input))!=EOF && c!='\n' && c!='#')
    	      s[i++] = c;
    	      
        if (c =='\n')
    	      s[i++] = c;
        else if (c == '#') {
             c=getc(input);
             while (c!='\n') {
                   c=getc(input);
                   s[i++] = '\n';
             }
        }
        s[i] = '\0';
        
        return i;
        
    }

    my table.c
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include "table.h"
    
    
    struct lineNode {
      int lineoccur;
      struct lineNode *next;
    };
    
    /*struct entryNode {
    	struct entryNode *next;
    	struct entry *row;
    };*/
    
    struct entry {
           char * symbol;
           int linedef;
           struct lineNode *occur;
           struct entry *next;
    };
    
    struct table {
           int entrycount;
           struct entry *first;
    };
    
    	/* returns an empty table */
    struct table * newTable( ) {
           struct table * table1 = malloc(sizeof(struct table));
           table1->first = NULL;
           table1->entrycount = 0;
           return table1;
    }
    
    struct entry *firstSymbol(struct table * symbols) {
    	//printf("the symbol is %s\n", symbols->first->symbol);
    	return symbols->first;
    }
    
    
    /* returns the result of adding a definition for the given symbol
       in the line with the given number to the table */
    struct table * addDef (char * symbol, int lineNum, struct table * symbols){
    
    	printf("should be abc is %s\n", symbols->first->symbol);
    	printf("!!!adding %s\n", symbol);
    	printf("should be abc is %s\n", symbols->first->symbol);
    
    	struct entry *newEntry = malloc(sizeof(struct entry));
    	newEntry->symbol = symbol;
    	newEntry->linedef = lineNum;
    
    	struct lineNode *o = malloc(sizeof(struct lineNode));
    	o->lineoccur = -1;
    	newEntry->occur = o;
    	//struct entryNode *newEntryNode = malloc(sizeof(struct entryNode));
    	//newEntryNode->row = newEntry;
    
    	printf("still adding %s\n", symbol);
    
    	if (symbols->entrycount == 0) {
    		symbols->first = newEntry;
    		symbols->entrycount = 1;
    		printf("1added here %s\n", symbols->first->symbol);
    		//printTable(symbols, "out");
    	}
    	else {
    		struct entry *nEntry = symbols->first;
    		while ( nEntry->next != NULL ) {
    			nEntry = nEntry->next;
    		}
    		nEntry->next = newEntry;
    		(symbols->entrycount)++;
    	}
    	return symbols;
    }
    
    
    struct table * addUse (char * symbol, int lineNum, struct table * symbols) {
    
    	printf("starting to add %s\n", symbol);
    	//printf("lineNum is %d\n", lineNum);
    	struct entry *nEntry = symbols->first;
    
    	if (symbols->first == NULL) {
    		//printf("going here\n");
    		struct entry *newEntry = malloc(sizeof(struct entry));
    		newEntry->symbol = symbol;
    		newEntry->linedef = -1;
    		struct lineNode *o = malloc(sizeof(struct lineNode));
    		o->lineoccur = lineNum;
    		newEntry->occur = o;
    		symbols->first = newEntry;
    		printf("added word!!!! %s\n", symbols->first->symbol);
    		symbols->entrycount = 1;
    		//printTable(symbols, "nothing");
    	}
    	else {
    		while ( nEntry->symbol != symbol) {
    			if (nEntry->next == NULL) {
    				struct entry *newEntry = malloc(sizeof(struct entry));
    				newEntry->symbol = symbol;
    				newEntry->linedef = -1;
    				struct lineNode *o = malloc(sizeof(struct lineNode));
    				o->lineoccur = lineNum;
    				newEntry->occur = o;
    				nEntry->next = newEntry;
    				(symbols->entrycount)++;
    				break;
    			}
    			nEntry = nEntry->next;
    		}
    		struct lineNode *o = nEntry->occur;
    		while ( (o->next != NULL) && (o->lineoccur != -1) ) {
    			o = o->next;
    		}
    
    		if (o->lineoccur == -1) {
    			o->lineoccur = lineNum;
    		}
    		else {
    			struct lineNode *newLineNode = malloc(sizeof(struct lineNode));
    			newLineNode->lineoccur = lineNum;
    			newLineNode->next = NULL;
    			o->next = newLineNode;
    		}
    
    	}
    	printf("finished adding use %s\n", symbols->first->symbol);
    	return symbols;
    }
    
    void processSymbol (char * symbol) {
    	char* word2 = symbol;
    
    	while (1) {
    		if (*symbol == '\n' || *symbol == ' ') {
    			*symbol = '\0';
    			symbol = word2;
    			break;
    		}
    		else {
    			symbol++;
    		}
    	}
    	printf("processed %s\n", symbol);
    }
    
    	/* print the table, in the format described above, to the given file */
    void printTable (struct table * symbols, FILE * out) {
        struct entry *n = symbols->first;
        printf("FIRST IS %s\n", symbols->first->symbol);
        //printf("%s", n->symbol);
    
    	while (n != NULL) {
    		//processSymbol(n->symbol);
        	printf("%s\t", n->symbol);
        	//printf("after");
        	printf("%d\t", n->linedef);
    
        	struct lineNode *nline = n->occur;
    
        	while ((nline != NULL) && (nline->lineoccur != -1)) {
        		printf("%d\t", nline->lineoccur);
        		nline = nline->next;
        	}
        	printf("\n");
    
        	fprintf(out, "%s\t", n->symbol);
        	fprintf(out, "%d\t\n", n->linedef);
        	n = n->next;
        }
    
    	printf("finished printing \n");
    }
    starting to add abc
    added word!!!! abc
    finished adding use abc
    FIRST IS abc <-- I added "abc" to the table
    abc -1 1 <-- table is fine with one entry
    finished printing
    should be abc is y: <--this should have been the first, "abc", as called from addDef
    !!!adding y:
    should be abc is y:
    still adding y:
    y: 2
    FIRST IS y:
    y: -1 1
    y: 2
    finished printing
    should be abc is abc:
    !!!adding abc:
    should be abc is abc:
    still adding abc:
    abc: 3
    FIRST IS abc:
    abc: -1 1
    abc: 2
    abc: 3
    finished printing
    starting to add y
    finished adding use y
    FIRST IS y
    y -1 1 4
    y 2
    y 3
    finished printing
    starting to add y
    finished adding use y
    FIRST IS y
    y -1 1 4 5
    y 2
    y 3
    finished printing
    FIRST IS y
    y -1 1 4 5
    y 2
    y 3
    finished printing

    why are my symbols getting replaced? when I just call the functions in table.c without reading from an input file, it adds and prints fine.
    Last edited by coni; 09-14-2009 at 03:08 AM.

  3. #18
    Registered User
    Join Date
    Oct 2006
    Location
    Canada
    Posts
    1,243
    Quote Originally Posted by BEN10 View Post
    Isn't it that the when the program has executed properly, the allocated memory is automatically freed and can be used somewhere else?
    honestly, i am not positive. i really thought it would stay reserved and thus wasted until OS reboot or until some other process the OS does to "clean up" memory at a later time, i.e. not immediately after the program executes--whether successful or not. i havent looked into those technical details in a number of years so maybe things are "better" now. edit: but i highly doubt it.
    Last edited by nadroj; 09-14-2009 at 08:57 AM.

  4. #19
    Registered User
    Join Date
    Oct 2006
    Location
    Canada
    Posts
    1,243
    i saw something like 8 'malloc' calls, and still no 'free' calls. are you reading what im saying? fix your memory leaks.

    Quote Originally Posted by coni View Post
    why are my symbols getting replaced? when I just call the functions in table.c without reading from an input file, it adds and prints fine.
    if this is true, then the only reason is that youre reading the input file incorrectly. i havent read all of your code again so i dont really remember it, but say your input file is this:
    Quote Originally Posted by input.txt
    abc
    def
    123
    456
    then in your program, for every read you do, print out what value it was, surrounded by quotes. surrounding it by quotes makes it obvious as to the "boundaries" of the value. if you dont have quotes (or whatever delimiter) then you may not notice a leading/trailing space/newline or other characters you dont expect. output after reading each value would be something like:
    Code:
    line #1 from file: 'abc'
    i see you have some output, but i can assume you arent doing this (printing out the values read from the file). because if you were, you would have also given us the contents of the file you were reading, so we can also verify it.

    again, this is assuming your code is correct, as you say, and that its just a problem with reading values from file.

  5. #20
    Registered User
    Join Date
    Sep 2009
    Posts
    16
    ok so I have mostly everything fixed now. I realized that I had been reusing the same char array and setting pointers to it, so it changed when I read in the next word. To fix that I used a strcopy instead. But when I print everything out, the first few times seem ok, and then I encounter a segfault

    main()
    Code:
    int main ( ) {
    	char line[MAXLINELEN];
    	char pline[MAXLINELEN];
    	char word[MAXWORDLEN];
    	int pos;
    
        input = fopen("table.test", "r");
    	output = fopen("table.out", "w");
    
    
    	struct table *p = newTable();
        int linecount = 1;
    
        //addUse("aaabc", 1, p);
        //addDef("yyyy:", 2, p);
    	
    	while (getline (line, pline, MAXLINELEN-1)) {
            //if (emptyLine(line) != -1) {
    		   pos = 0;
               while (1) {
                     if ((pos = nextWord (line, pos, word, linecount, p)) == -1) {
                    	 break;
                     }
                     printTable(p, output);
                     //this prints fine but eventually reaches a segfault
               }
               linecount++;
    
        }
        printTable(p, output);
         if I take out the looping printTable and only keep this one it doesn't print, only segfaults
          fclose(input);
    	fclose(output);
    	return 0;
    }
    printTable in table.c
    Code:
    void printTable (struct table * symbols, FILE * out) {
        struct entry *n = symbols->first;
    //this line is causing the segfault
    
    	while (n != NULL) {
        	printf("%s\t", n->symbol);
        	printf("%d\t", n->linedef);
        	fprintf(out, "%s\t", n->symbol);
        	fprintf(out, "%d\t", n->linedef);
    
        	struct lineNode *nline = n->occur;
    
        	while ((nline != NULL) && (nline->lineoccur != -1)) {
        		printf("%d\t", nline->lineoccur);
        		fprintf(out, "%d\t", nline->lineoccur);
        		nline = nline->next;
        	}
        	printf("\n");
        	fprintf(out, "\n");
    
    
        	n = n->next;
        }
    	printf("finished printing \n");
    }
    nextWord that main() calls
    Code:
    int nextWord (char *str, int pos, char *word, int linecount, struct table *p) {
    
    	if (emptyLine(str) == -1) {
    		return -1;
    	}
        int i=0; 
        while (1) {
    	      if (*str == '\n' || *str == '\0' || *str == '#')
                   return -1;
              else if (i == pos) {
    	           break;
              }
    	      else {
    	           i++;
    	           str++;
              }
        }
        int r = pos;
    
        if (emptyLine(str) == -1)
        	return -1;
    
        char* word2 = word;
        int j;
        for (j=0; *str!='\n' || *str!=EOF; str++) {
    	    if (*str >= 33 && *str <= 126) {
    	        char c = *str;
    	        //firstSymbol(p);
    	        while (c != '\n' && c != ' ') {
    		          r++;
    		          *word = c;
    		          word++;
    		          str++;
    		          c = *str;
                }
    	        *word = '\0';
    	        char last = *--word;
               if (last == ':') {
            	   *word = '\0'; //takes out the ':' character
    
    I'm using strcpy here so why would it print out find and then the p->first point again to null?
            	   char * newString = malloc(sizeof(strlen(word2)));
            	   strcpy(newString, word2);
            	   addDef(newString, linecount, p);
                }
               else {
            	   char * newString = malloc(sizeof(strlen(word2)));
            	   strcpy(newString, word2);
            	   addUse(newString, linecount, p);
            	   return r;
                }
                break;
    	    }
    	    else {
    	        r++;
                j++;
    	    }
        }    
        word = word2;
    
        return r;
    }

  6. #21
    Registered User
    Join Date
    Oct 2006
    Location
    Canada
    Posts
    1,243
    - it seems you have a lot of pointer arithmetic and looping which is huge potential for logic errors such as those your experiencing with the dynamic memory. i would review those algorithms/loops and trace it on paper. if you trace a single, just one, runthrough of your program, with adding just one or maybe two elements to your table, you will solve it. this is somewhat tedious, however it is very common to do (i.e. in algorithms courses and in general debugging) and it is a near-guaranteed way of solving your problem, down to the exact line. (i say near-guaranteed because it may be some external thing, such as OS, disk space, permissions, etc, that cant be verified with your code on paper).

    - you still do not have "free" calls, who knows, maybe your program is fine but due to all of the memory leaks its breaking something? fix this. otherwise i will stop donating my time giving you suggestions if you dont implement or even at least comment on them saying your not going to implement them for whatever reason.

    - you didnt post your "addUse" and "addDef" functions with your latest updated code (could the problem be in there?)

    - have you verified there is no logic error in your file IO? you should strip your code down to the minimum possible (file IO shouldnt be required to test your code, just use std/console IO), to reduce complexity and to minimize introducing problems. i.e., does the program run fine with STD IO and no calls to "printTable"? try and partition the problem like this.

    anyways, it seems you do some code, run into a problem, post here, get input or a solution and implement it (or not even implement it), and go on to adding more functionality/code. you should verify that your initial problem (whatever that even was, i dont remember) is indeed fixed. that is, go back to that initial "fixed" code here, and test it with adding 0, 1, 5, 100, 1000+ entries (though you may run out of memory due to all of your memory leaks). test it with weird input strings and numbers. then move on to working with files, or printing it, or whatever it is your trying to do. when you test an algorithm/program with one set of input, it means nothing. only when you test it with "sufficiently large" variety of inputs can you gain some confidence that it "works".

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Malloc for an Array of Structs
    By pseudonoma in forum C Programming
    Replies: 3
    Last Post: 03-26-2008, 01:55 PM
  2. Malloc with structs.
    By jrdoran in forum C Programming
    Replies: 4
    Last Post: 12-11-2006, 11:26 PM
  3. malloc for structs and arrays
    By rkooij in forum C Programming
    Replies: 15
    Last Post: 05-04-2006, 07:38 AM
  4. malloc
    By bazzano in forum C Programming
    Replies: 3
    Last Post: 04-19-2006, 09:53 AM
  5. Creating a pointer to an array of structs
    By Jonathan_ingram in forum C Programming
    Replies: 8
    Last Post: 12-31-2003, 08:49 AM