LinuxQuestions.org
Review your favorite Linux distribution.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 01-16-2009, 12:38 PM   #1
aatwell
Member
 
Registered: Apr 2007
Location: San Jose, CA
Posts: 31

Rep: Reputation: 15
C to Reverse a Text File.


Greetings,
Anyone have a bit of C code that will read a text file and output the lines of text in reverse order? For instance a text file with...
Code:
one
two
three
four
five
will be output to a file containing....

Code:
five
four
three
two
one
many thanks.
 
Old 01-16-2009, 12:44 PM   #2
colucix
LQ Guru
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,509

Rep: Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983
You can take a look at the tac source code. You will find it in the GNU coreutils sources.
 
Old 01-16-2009, 12:51 PM   #3
navderm
Member
 
Registered: Dec 2008
Location: Chandigarh, India
Distribution: Red Hat 9
Posts: 67

Rep: Reputation: 15
I guess using dynamic string arrays and saving each line. and then calling them in opposite sequence to save it should make this easy...
Does this not work???
 
Old 01-16-2009, 12:55 PM   #4
aatwell
Member
 
Registered: Apr 2007
Location: San Jose, CA
Posts: 31

Original Poster
Rep: Reputation: 15
That's what I've been trying to do and I get all kinds of errors....So I was looking for a canned solution.
 
Old 01-16-2009, 01:10 PM   #5
navderm
Member
 
Registered: Dec 2008
Location: Chandigarh, India
Distribution: Red Hat 9
Posts: 67

Rep: Reputation: 15
it would be better if you could try yourself and post your errors and if possible code...
would help you learn better...
 
Old 01-16-2009, 01:45 PM   #6
aatwell
Member
 
Registered: Apr 2007
Location: San Jose, CA
Posts: 31

Original Poster
Rep: Reputation: 15
Ok folks, Here's what I have and what i get.... Any help would be greatly appreciated.


Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SIZE 256

int main()
{       // DECLARE VARIABLES //
	int a; int i; FILE *Fin; 
	char *line = NULL; 
	char *tempstr;
	char *filename = "./mytxt.txt";
	size_t len = 0; ssize_t read;
	Fin = fopen(filename, "r");
	int LineCount; LineCount = 0;

        // DETERMINE NUMBER OF LINES //
        while ((read = getline(&line, &len, Fin)) != -1)
        {
           LineCount = LineCount + 1;
        }
        if(line)free(line); fclose(Fin);

        // FEEDBACK //
        printf("\n\n\n LineCount = %d", LineCount);

        // CREATE STRING ARRAY WITH EXACT AMOUNT OF STRINGS NEEDED //
        char myarrayofstrings[LineCount][SIZE];

        // INPUT LINES INTO ARRAY //
        Fin = fopen(filename, "r");
        for(i = 1; i < LineCount + 1; i++)
        {
	   read = getline(&line, &len, Fin);
           strncpy(myarrayofstrings[i], line, strlen(myarrayofstrings[i]));
           myarrayofstrings[i][strlen(line)] = '\0';
        }
        fclose(Fin);

        // OUTPUT TO SCREEN FOR TESTING...WHEN WORKING PUT TO FILE. //
        for(a = 1; a < LineCount + 1; a++)
        {
           printf("%s\n", myarrayofstrings[a]);
        }

        return(0);
}

Output is this garbage...
Code:
 LineCount = 12

three
four
f
six
sev
e

ten101010
e
twelv
 
Old 01-16-2009, 01:46 PM   #7
aatwell
Member
 
Registered: Apr 2007
Location: San Jose, CA
Posts: 31

Original Poster
Rep: Reputation: 15
Oh! I forgot... Here's the Fin file.....

Code:
one1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
two2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
three33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333
four444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444
five555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555
six6666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666
seven77777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777
eight88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
nine999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
ten1010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010
eleven1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
twelve1212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121
 
Old 01-16-2009, 01:53 PM   #8
indienick
Senior Member
 
Registered: Dec 2005
Location: London, ON, Canada
Distribution: Arch, Ubuntu, Slackware, OpenBSD, FreeBSD
Posts: 1,853

Rep: Reputation: 65
How about the following algorithm:
Code:
1. Open the file.
2. Scan through the file collecting the locations of newline characters stopping when you hit EOF.
2a. Each time you find a newline character, increment a counter by 1.
2b. Add the location of the EOF character as the last element of the array, and increment the counter.
3. Iterate, backwards, through the array of newline locations, offsetting the start point by -1 (so you start at the element before the EOF character). (Hint: Use the counter.)
3a. Upon each iteration (starting with the initial run), copy the text between newline_location[x] and newline_location[x + 1] to a new file.
 
Old 01-16-2009, 02:51 PM   #9
johnsfine
LQ Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,286

Rep: Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197
Quote:
Originally Posted by aatwell View Post
char myarrayofstrings[LineCount][SIZE];
Arrays in C are indexed 0 through size minus one, so the valid indexes of myarrayofstrings would be 0 through LineCount-1.

Quote:
for(i = 1; i < LineCount + 1; i++)
But instead (and in both your loops) you use 1 through LineCount.

That corrupts the section of the stack where your local variables are stored, producing results that would be very hard to predict. The results you got don't fit what I would expect for that bug, so I looked for the next bug but didn't see it. It is hard enough to predict the consequences of the first bug, that I'm not sure there is a next one.

BTW, I assume this is a homework question. I would not have been as helpful as posts 2 and 3 of this thread to the apparent homework question in posts 1 and 4 (that is absolutely the wrong way to look for homework help). But post 6 deserved some help, homework or not.

Last edited by johnsfine; 01-16-2009 at 02:57 PM.
 
Old 01-16-2009, 03:11 PM   #10
aatwell
Member
 
Registered: Apr 2007
Location: San Jose, CA
Posts: 31

Original Poster
Rep: Reputation: 15
Thanks johnsfine,
It's not a homework question. I'm not in school. It's for a web page I'm designing on my own.

I fixed the 0 to LineCount loops and I still get the same garbage result.

:-(
 
Old 01-16-2009, 03:14 PM   #11
johnsfine
LQ Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,286

Rep: Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197
Quote:
Originally Posted by aatwell View Post
if(line)free(line);
That's another bug. At the end of the first loop you free the buffer allocated by getline, but in the second loop you continue to use that buffer.
 
Old 01-16-2009, 04:02 PM   #12
paulsm4
LQ Guru
 
Registered: Mar 2004
Distribution: SusE 8.2
Posts: 5,863
Blog Entries: 1

Rep: Reputation: Disabled
Hi -

There are a number of things in the program I'd probably do differently ... but here is the basic program with a few (relatively minor!) corrections:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SIZE 256

int main()
{       // DECLARE VARIABLES //
        int a; int i; FILE *Fin;
        char *line = NULL;
        char *tempstr;
        char *filename = "./mytxt.txt";
        size_t len = 0; ssize_t read;
        Fin = fopen(filename, "r");
        int LineCount; LineCount = 0;

        // SANITY CHECK: DID FILE GET OPENED?
        if (Fin == NULL)
        {
          perror ("could not open mytxt.txt!");
          return 1;
        }

        // DETERMINE NUMBER OF LINES //
        while ((read = getline(&line, &len, Fin)) != -1)
        {
           LineCount = LineCount + 1;
        }
        if(line)
          free(line);
        fclose(Fin);

        // FEEDBACK //
        printf("\n\n\n LineCount = %d", LineCount);

        // CREATE STRING ARRAY WITH EXACT AMOUNT OF STRINGS NEEDED //
        char myarrayofstrings[LineCount][SIZE];

        // INPUT LINES INTO ARRAY //
        Fin = fopen(filename, "r");
        if (Fin == NULL)
        {
          perror ("File reopen error");
          return 1;
        }
        line = NULL;
        len = 0;
        read = 0;
        for(i = 0; i < LineCount; i++)
        {
           read = getline(&line, &len, Fin);
           if (read > 0)
           {
             line[strlen(line) - 1] = '\0';
             strncpy(myarrayofstrings[i], line, SIZE);
           }
        }
        fclose(Fin);

        // OUTPUT TO SCREEN FOR TESTING...WHEN WORKING PUT TO FILE. //
        for(a = 1; a < LineCount + 1; a++)
        {
           printf("%s\n", myarrayofstrings[a]);
        }

        return(0);
}
Per Johnsfine - "getline()" allocates the buffer. Freeing it is fine; not freeing it would be fine, too - it doesn't matter.

The biggest two problems in the original code were:
a) Not checking for error conditions (like file open failure)
b) Not delimiting the input string in the right place.

I prefer to call "strncpy()" with the size of my buffer (here, "SIZE"). And there's no harm in delimiting the original string ("line") instead of your final buffer.

'Hope that helps .. PSM
 
Old 01-16-2009, 04:14 PM   #13
jim mcnamara
Member
 
Registered: May 2002
Posts: 964

Rep: Reputation: 36
Here a way to do it when you assign a recursion problem:
Code:
/* tac = cat backwards, i.e., reverse line order using recursion 
*        fails on files with line lengths > 127
*        usage: tac file1 [file2...]
*	            [source command] | tac  
*               tac < file1
*        limited error checking 
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAX_REC_LEN 128
#define ck(x) if((x)==NULL)\
{perror("file open or memory failure"); exit(EXIT_FAILURE);}

/* recursive read line */
void dumpline(FILE *in)
{
    char tmp[MAX_REC_LEN]={0x0};
	
    if(fgets(tmp, sizeof(tmp), in)==NULL)
    {
    	if(!feof(in))
    	{
			perror("File input error");
			exit(EXIT_FAILURE);
		}
        return;
	}    		
	dumpline(in);
    fprintf(stdout, "%s", tmp);
}

int main(int argc, char **argv)
{
	int i=1;
	
	if (argc > 1)
	{		
		while(i < argc)
		{
			FILE *in=fopen(argv[i++],"r");
			ck(in);
			dumpline(in);
			fclose(in);
		}
	}
	else
		dumpline(stdin);
	return 0;	   
}
FWIW - this kind of problem is solved easily with recursion. It also may blow a stacksize limit, if one is set, when run on huge files, so it is not perfect by any means. This doesn't help the OP but it is one easy way to solve the problem.

Last edited by jim mcnamara; 01-16-2009 at 04:15 PM.
 
Old 01-16-2009, 04:24 PM   #14
johnsfine
LQ Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,286

Rep: Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197
Quote:
Originally Posted by paulsm4 View Post
"getline()" allocates the buffer. Freeing it is fine;
But continuing to use it AFTER you free it is not fine. Your corrections leave that bug. Maybe you misunderstand getline()

getline() only allocates the buffer if the pointer and length are zero. Otherwise, it may reallocate the buffer if the length is too small.

Quote:
not freeing it would be fine,
Yes, because the OS frees all the memory when the program exits.

There are a lot of things, including freeing the buffer at the correct time that a professional programmer should do differently (so it wouldn't become a memory leak if this code became part of a larger project). I didn't want to comment on any of that, just on things that would make it fail.

Quote:
it doesn't matter.
Failing to delete the buffer where you ought to doesn't matter. Deleting it where it shouldn't be deleted very much does matter. (I just happened to miss that bug on first look).

Quote:
The biggest two problems in the original code were:
a) Not checking for error conditions (like file open failure)
b) Not delimiting the input string in the right place.
There are lots of flaws in not covering exception cases of possible wrong inputs, but the biggest two (or more if I missed some) problems are the ways in which it corrupts memory even if the input is perfect.

Quote:
And there's no harm in delimiting the original string ("line") instead of your final buffer.
I thought getline() did that for you (I'm not sure because I never used getline). If getline() does then doing it over is pointless. If getline doesn't delimit the string then strlen(line) is wrong, so your suggestion
Quote:
line[strlen(line) - 1] = '\0';
is at best pointless and otherwise is dangerously wrong.

Last edited by johnsfine; 01-16-2009 at 04:26 PM.
 
Old 01-16-2009, 06:01 PM   #15
PTrenholme
Senior Member
 
Registered: Dec 2004
Location: Olympia, WA, USA
Distribution: Fedora, (K)Ubuntu
Posts: 4,187

Rep: Reputation: 354Reputation: 354Reputation: 354Reputation: 354
Here's my (somewhat shorter) version, but I think the recursive solution by jim mcnamara is quite nice.

PHP Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

extern FILE stderr;
extern FILE stdin;
#define BUFFER_STEP 1024

int main(int argcchar *argv[])
{       
// DECLARE VARIABLES //
    
int i;
    
FILE *Fin
    
char *line NULL
    
char **Buffer;
    
size_t len 0;
    
ssize_t read;
    
int LineCount 0;
    
int BufferSize 0;

    
// Open the input file
    
Fin = (argc 1) ? fopen(argv[1], "r") : stdin;
    if (!
Fin) {
      
fprintf(stderr,"%s: Could not open %s for input.\n"argv[0], (argc 1) ? argv[1] : "stdin");
      return(
1);
    }

    
// Determine number of lines and buffer the input//
    
Buffer calloc((size_tBUFFER_STEPsizeof(char *));
    if (!
Buffer) {
      
fprintf(stderr"%s: Out of memory at initial buffer allocation.\n"argv[0]);
      return(
1);
    }
    
BufferSize += BUFFER_STEP;
    while ((
read getline(Buffer[LineCount++], &lenFin)) > -1)
    {
      if (
LineCount BufferSize) {
        
BufferSize += BUFFER_STEP;
        
Buffer realloc(BufferBufferSize);
        if (!
Buffer) {
          
fprintf(stderr"%s: Out of memory increasing buffer size to %d lines.\n"argv[0], BufferSize);
          return(
1);
        }
      }
      
Buffer[LineCount] = NULL;
    }
    
fclose(Fin);

    
// Feedback
    
printf("\n%s: LineCount = %d\n"argv[0], LineCount);

    
// Output to screen for testing...When working put to file. //
    
for(LineCounti;)
    {
      
printf("%s\n"Buffer[--i]);
    }
    
    
// Clean up
    
while (*Bufferfree(*Buffer);
    
free(Buffer);

    return(
0);

 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
How to parse text file to a set text column width and output to new text file? jsstevenson Programming 12 04-23-2008 02:36 PM
reverse order some lines of text files Melsync Programming 4 09-20-2005 04:40 PM
vi showing all text in red reverse video paultaylor Linux - Software 2 11-12-2004 09:36 AM
Reverse Sort Text File BxBoy Linux - General 1 08-02-2004 10:13 AM
Reverse and Squeezing of text of character in C egoleo Programming 1 03-19-2004 09:45 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 02:38 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration