Thread: Arrays - passing, realloc

  1. #1
    Registered User
    Join Date
    Feb 2010
    Posts
    9

    Unhappy Arrays - passing, realloc

    Hello,
    I'm taking a C class, and stuck on an assignment. I know the prog has a few more kinks in it, but I've hit a wall.
    In the func read_into_array(), **line_array is supposed to get filled by values read in from a file. When I do a printf of it, each element has the last value read in from the file!!
    The assignment is to take lines from a file, formatted like this:
    Doe,John 85
    and sort them by score, with ties broken by name, into another file.

    Code:
    /*      CIS 15BG
     *      Lab #3
     *      Due Date:       2/9/10
     */
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include "perry.h"
    #define BUCKET_SIZE 5
    #define LINE_LEN 100
    
    char *name_score_swap(char *score_line);
    
    void main(int argc, char **argv)
    {
           void checkargs(int numargs, char **args, FILE **fpin, FILE **fpout);
           char **read_into_array(FILE **fpin);
           void sel_sort_scores(FILE **fpout, char **line_array);
    
           char **line_printer, **line_array;
           FILE *fpin, *fpout;
    
           checkargs(argc, argv, &fpin, &fpout);
           line_array = read_into_array(&fpin);
           sel_sort_scores(&fpout, line_array);
    
           for(line_printer = line_array; *line_printer; line_printer++)
    	       fputs(name_score_swap(*line_printer), fpout);
    }
    
    void checkargs(int numargs, char **args, FILE **fpin, FILE **fpout)
    {
    	if(numargs != 3)
    	{
    		printf("Usage: %s infile outfile\n", args[0]);
    		exit(EXIT_FAILURE);
    	}
    
    	*fpin = Fopen(args[1], "r");
    	*fpout = Fopen(args[2], "w");
    }
    
    char **read_into_array(FILE **fpin)
    {
    	char buffer[LINE_LEN + 1], **lineptr, **line_array;
    	int lines = 0;
    	int i;
    
    	line_array = (char **) Malloc(BUCKET_SIZE * sizeof(char *));
    	lineptr = line_array;
    
    	while(fgets(buffer, LINE_LEN + 1, *fpin))
    	{
    		*lineptr = (char *) Malloc((strlen(buffer) + 1) * sizeof(char));
    		*lineptr = name_score_swap(buffer);		
    		
    		lines++;
    		if(lines % BUCKET_SIZE == 0)
    			line_array = (char **) Realloc(line_array, 
    					(BUCKET_SIZE + lines) * sizeof(char *));
    		lineptr = line_array + lines;
    	}	
    	*lineptr = '\0';
    	for(i=0;i<10;i++)
    	printf("%p\n", line_array[i]);
    	Fclose(*fpin);
    	return(line_array);
    }
    
    void sel_sort_scores(FILE **fpout, char **line_array)
    {
    	char **mover, **shaker, **temp;
    	
    	for(mover = line_array, shaker = mover + 1; *mover; mover++)
    	{
    		printf("%p", mover);
    		while(*shaker)
    		{
    			if(strcmp(*mover, *shaker))
    			{
    				*temp = *mover;
    				*mover = *shaker;
    				*shaker = *temp;
    			}
    			printf("%d\n", **mover);
    			shaker++;
    		}
    	}
    }
    
    char *name_score_swap(char *score_line)
    {
    	char *temp, *ptr;
    	temp = (char *) Malloc((strlen(score_line) + 1) * sizeof(char));
    
    	ptr = strchr(score_line, '\040');
    	*ptr = '\0';
    	strcpy(temp, ptr + 1);
    	strcat(temp, "\040");
    	strcat(temp, score_line);
    	return(strcpy(score_line, temp));
    }

  2. #2
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Not to derail your love affair with double pointers, but there is a very easy and no pointer way to do this. (OK, you can use 1 pointer array if you want).

    The trick is to build an index array (I use int's), and initialize them:

    This is a *very* slick trick to keep in your toolbox for coding, imo. You can use it with any sort you want, even Quicksort.


    Edit:

    A more complete example of what I was referring to:

    Code:
    /* shows a 2 key simple sort done through an index
    
    status: ok, not thoroughly tested
    
    */
    
    #include <stdio.h>
    #include <string.h>
    
    #define SIZE 7
    #define COL 15
    
    int main() {
      int i, j, temp, key2;
      int index[SIZE];
      int score[SIZE] = {20, 20, 10, 15, 43, 38, 38};
      char name1[SIZE][COL]={"David", "Baker","Edward", "Charly","Frank","Gina", "Abe"};
      char name2[SIZE][COL]={"Dave2","Bake2","Ed2","Charly2","Frank2","Gina2","Abe2"};
      
      for(i = 0; i < SIZE; i++)
        index[i] = i;                               //   << simple no? :p
    
    /*  for(i = 0; i < SIZE; i++)
        printf("\n%d", index[i]);                              
    */
    
    /*
    now you can put each name and each score, into it's own array:
    name1, name2, and score I'll call them. Then sort them according to 
    score - but ONLY sort the index, not the actual scores or names.
    In a simple sort:
    */
    
      for(i = 0; i < SIZE; i++)  {
        for(j = i + 1; j < SIZE; j++) {
          if(score[index[i]] > score[index[j]]) {
            temp = index[i];
            index[i] = index[j];
            index[j] = temp;
          }
          if(score[index[i]] == score[index[j]]) {     // sort by the secondary key
            key2 = strcmp(name1[index[i]], name1[index[j]]);
            if(key2 > 0) {
              temp = index[i];
              index[i] = index[j];
              index[j] = temp;
            }
          }
        }   
      }
      
      //now, when you want to print out the sorted arrays, you use the index
      for(i = 0, j = 0; i < SIZE; i++, j++) {
        printf("\n %d  %s  %s", score[index[i]],  name1[index[i]], name2[index[i]]);
      }
      printf("\n\n\t\t\t     press enter when ready");
      i = getchar();
      return 0;
    }
    Simple, direct, and although you wind up with sorted data, the data itself is not moved from it's original position. IMO, that's pretty slick.
    Last edited by Adak; 02-08-2010 at 09:24 AM.

  3. #3
    Registered User
    Join Date
    Feb 2010
    Posts
    9
    Hmm. I appreciate the help.
    My love affair is by direct instruction from my prof; he despises indexing. I could be mistaken, but for this assignment, that is, for multidimensional arrays it's accepted. I'll have to go reread the spec. The example you have is much simpler. So maybe I'll just rewrite it.

    But, I'm still totally confused on why my code fills each element of a pointer array with the same address?

  4. #4
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Despises indexing?? Well, that figures I suppose.

    Three things I noticed in your code:

    1) In sel_sort, you use if(strcmp()), which will swap whether the strings are > or < each other, since only zero will fail that test. I'm sure you want if((strcmp() > 0).

    2) In two places you use the word malloc() with a capital 'M'. C is case sensitive, so your compiler should give you an error on those.

  5. #5
    Registered User
    Join Date
    Feb 2010
    Posts
    9
    I guess I was mistaken about if conditions. And I should have mentioned that perry.h includes wrapper funcs for error checking, i.e. Fopen, Malloc...

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Arghh passing 2D arrays to a func gives errors
    By bryce in forum C Programming
    Replies: 8
    Last Post: 09-12-2009, 11:24 AM
  2. Passing Arrays to Functions...
    By txcs in forum C++ Programming
    Replies: 4
    Last Post: 04-22-2009, 10:36 AM
  3. passing structure arrays to functions?
    By bem82 in forum C Programming
    Replies: 3
    Last Post: 10-30-2006, 06:17 AM
  4. passing two dimensional arrays
    By Nova_Collision in forum C++ Programming
    Replies: 3
    Last Post: 02-04-2003, 01:47 PM
  5. passing arrays to functions
    By Unregistered in forum C Programming
    Replies: 3
    Last Post: 03-01-2002, 03:18 PM