views:

699

answers:

4

Hi,

I was trying to make a simple bubblesort program.

Read in numbers from a text file and compare them with the next line, sort in ascending order.

Now, I've found my program is able to read from the file just fine, it's when I use any write commands (fprintf, or fputs) that everything goes wrong.

I've tried using ftell and fseek and I had the same issue.

Assuming the text file contains:

1804289383
846930886
1681692777
1714636915
1957747793
424238335
719885386
1649760492
596516649

It gets stuck in an infinite loop with

846930886

846930886
8804289383
8804289383 ...

as the output to the file and 8804289383 repeating over and over

int main(void) {

int swapped;
int run_once;

// pointers

FILE *filep;

// file positions

fpos_t currpos;
fpos_t prevpos;
fpos_t nextpos; 

   /**
     * next pos helps represent where the file pointer was 
     * before the switch was initiated
   */

// swap variables

unsigned long long int prev;
unsigned long long int curr;

// string inputs

char buffer[20];

// open file stream

filep = fopen("dataFile.txt","r+"); // looks for the file to open for r/w

if (filep == NULL) {      // check for file
 fprintf(stderr, "dataFile.txt does not exist!!\n");
 return 1;
}


// bubble sort

do {
 rewind(filep); // starts the pointers at the start of the file

 fgetpos(filep,&currpos);
 prevpos = currpos;
 nextpos = currpos; 


 swapped = 0; // swapped = false

 curr = 0;
 prev = 0;


 fgets(buffer, 20, filep); // need to read before loop or else it doesn't end properly  


 while (!feof(filep)) {  // while it's not the end of the file

  fgetpos(filep,&nextpos);

  sscanf(buffer,"%lld",&curr); // convert to unsigned long long


  printf("Prev: %lld\n",prev); // troubleshooting stuff
  printf("Curr: %lld\n",curr);

  if (prev > curr) {  
   fsetpos(filep,&prevpos); // move filep to previous
   fprintf(filep,"%lld\n",curr); // print current to previous spot

   fsetpos(filep,&currpos); // move filep to current
   fprintf(filep,"%lld\n",prev); // print previous to current spot

   printf("Swapped!\n"); // more troubleshooting

   swapped = 1;  // swapped = true

   fsetpos(filep,&nextpos); // reset filep by moving it to nextpos
  }


  if (prev < curr) {
   prev = curr; // no need to swap since prev will continue to be the previous value 
  }


  // increment the postions
  prevpos = currpos;
  currpos = nextpos;

  fgets(buffer, 20, filep);
  }

} while (swapped == 1);


// close file stream

fclose(filep); 

return 0;

}

Thanks you very much for your help, because I've spent over 10 hours trying to figure out how to fix this with no luck.

+2  A: 

Hmm, I might reconsider the approach.

  • Is it really your intention to do an external sort? If not, it would be a lot cleaner to just read the file in, sort it in memory, and then write it out.
  • Regardless of the previous answer, is it really necessary to sort in place? Even for an external sort, would it be within your problem parameters to write out a new file instead of trying to bash a single file into sorted order?
  • I guess bubble sort is the one kind of sort that will actually work while editing a text file with variable-length-lines in place, because whenever you want to write a long number on to a short line you also have a short number and a long line right next to it. (Shudder)

If you really do want to do an external sort in place, then my suggestion is that you refactor the operations into small functions so you can decompose the necessary logic without getting confused.

Update: Forget the above advice, I've decided I like this problem just the way it is. Unfortunately I've already read Yuliy's answer.

DigitalRoss
The more I think about this problem the more I like it. I am so tempted to write it for you...
DigitalRoss
Yes, one of the requirements was I an external sort.You are right I could have used two text files and just searched for the smallest and then append it an output file. Then I would just need int variables to keep track of what is was the last number I wrote, the current smallest number in my current search andsome next number to compare.Normally I would have read the file into memory as well. Also the text file I am using is actually much larger, I just chose to test with a few lines of it, instead of all 1000 of them.
Kibbles n Bits
+1  A: 

You're not going to be able do that in the general case since your numbers have differing numbers of characters. You should just read in all the numbers, sort in memory, and then overwrite the existing file with a new file containing the sorted numbers.

Jim Buck
See my answer. For a bubble sort you _can_ do this reasonably , since a swap of adjacent numbers doesn't move anything else around.
Yuliy
+2  A: 

Your code to swap two adjacent characters is flawed. Note that if you have two numbers 1 and 234, they appear inside the file initially as 1\n234\n, but if swapped, the 1 does not start at index 2 in the file (where the 234 initially started), but instead at index 4.

As a result, if you swap two numbers prev and curr, with prev being the earlier of the two numbers in the file initially, place curr at prev's position, and prev after the newline after you finished writing curr. Note that this is a local change (since the len(prev) + len(curr) == len(curr) + len(prev).

Yuliy
Bubble Sort will work in-place on the file... but it's still going to be *horribly slow* vs reading the file into memory, sorting in memory, and writing the file back out from memory.
Adisak
Thank you! The 1\n234\n was just what I needed. I was visualizing it the way notepad would display the text file, each pointer pointing to the start of a new line, not like a continuous string. That's part of the reason why I couldn't understand why it was outputting that weird number "8804289383", but it should have tipped me off that the pointers were not 'lining up'.Thanks again!
Kibbles n Bits
A: 

Add some stuff to your troubleshooting and you should see your probably come up pretty quickly: printf("CurPost: %d\n",currpos); printf("PrevPos: %d\n",prevpos); printf("NextPos: %d\n",nextpos);

(hint: your numbers are different lengths so your currpos and nextpos numbers end up one place out, because some numbers are different lengths than other numbers).

Your program will only work if every number on each line of the file is the same size. Even then you have some other problems, like the last number in the file will never move.

myforwik