ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
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???
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.
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.
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.
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.
"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.
int main(int argc, char *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_t) BUFFER_STEP, sizeof(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++], &len, Fin)) > -1) { if (LineCount > BufferSize) { BufferSize += BUFFER_STEP; Buffer = realloc(Buffer, BufferSize); 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);
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.