I need to write a program in C, that prints out last five lines of file by using basic functions like open, read, write, close, lseek. My code so far:
int main(int argc, char *argv[]){
int fd1=open(argv[1], O_RDONLY);
char c;
int currPos = lseek(fd1,-2,SEEK_END);
while(currPos != -1){
read(fd1,&c,sizeof(c));
currPos--;
currPos=lseek(fd1,currPos,SEEK_SET);
if (c == '\n'){
}
}
return 0;
}
Can anybody help me? I think I need to store those characters in array and then print it backwards, but I don't know how.
Why not count the number of characters read while reading back to the fifth newline (call that n) and then do a read of n characters? You don't need to store the data, it's already stored in the file.
Inside the if statement you can count how many '\n' characters you encounter from the end of your file. When you encounter the 6th end-of-line, you know you are at the end of the 6-th-from-the-end line (assuming that the last line also contains an end-of-line character at the end) , so you just print from that point to the end of the file.
You do not need to save the characters in an array, since they are already saved in your file.
You can just do (after your while loop):
int i=read(fd1,&c,1);
while(i){
printf("%c",c);
i = read(fd1,&c,1);
}
It may not be the most efficient way to do it, but it should do the trick.
Note: There is no need to write sizeof(c), since c is a char, and chars are always 1 byte long.
Also, you should always check the return value of read, you never know when something goes wrong in your system and your program crashes because of a read gone wrong.
Related
I am trying to understand some C code I've stumbled across. For the record, the code does exactly what it's supposed to except for the print line I added. It takes all of the contents from the inputFile.txt, and replaces the J's with X's, and writes it to the outputFile.txt.
int main(void) {
int fd_to_read = open("inputFile.txt", O_RDONLY);
int fd_to_write = open("outputFile.txt", O_WRONLY | O_CREAT);
char c;
int bytes;
while ((bytes = read(fd_to_read, &c, sizeof(c))) > 0) {
if (c == 'J') {
c = 'X';
}
write(fd_to_write, &c, sizeof(c));
//I added this and it doesn't work.
printf(&c);
}
close(fd_to_read);
}
When I first saw this, I expected the while loop to print the first character from the file over and over again. I understand that the read() function will be executed until it is >0, but I assumed that in order for it to change position in the file the memory address pointed to by c would have to increment by something, possibly the sizeof(c), but nothing appears to increment and it just moves on to the next letter in the file. My next assumption is that read() handles that on it's own, but when I went to print the contents of &c I got close to what I expected, which was a ton of garbage, since it was just printing random things from memory essentially.
So, two questions really.
How is the &c that is written to the outputFile.txt write to that correctly without incrementing the address of c?
How would I just print the individual characters from the file without all the garbage since print(&c) added all the garbage after each char?
Ok two things.
(1) char c does not need to be incremented because it is serving like the output to the read fn.
(2) the read and write fn's automatically increment their respective file descriptors.
The file descriptors (fd_to_read, fd_to_write) represent a location in the file, not char c.
Read about it in the man pages:
https://linux.die.net/man/3/read
https://linux.die.net/man/3/write
char c; ... printf(&c); is UB, yet I suspect OP knows that.
The first arg to printf() must be a pointer to a string. &c is not a pointer to a string.
OP is hoping for favorable UB. Good luck.
Say I make an input :
"Hello world" // hit a new line
"Goodbye world" // second input
How could I scan through the two lines and input them separately in two different arrays. I believe I need to use getchar until it hits a '\n'. But how do I scan for the second input.
Thanks in advance. I am a beginner in C so please It'd be helpful to do it without pointers as I haven't covered that topic.
Try this code out :
#include<stdio.h>
int main(void)
{
int flx=0,fly=0;
char a,b[10][100];
while(1)
{
a=getchar();
if(a==EOF) exit(0);
else if(a=='\n')
{
flx++;
fly=0;
}
else
{
b[flx][fly++]=a;
}
}
}
Here I use a two dimensional array to store the strings.I read the input character by character.First i create an infinite loop which continues reading characters.If the user enters the end of File character the input stops. If there is a newline character then flx variable is incremented and the next characters are stored in the next array position.You can refer to the strings stored with b[n] where n is the index.
The function that you should probably look at is fgets. At least on my system, the definition is as follows:
char *fgets(char * restrict str, int size, FILE * restrict stream);
So a very simple program to read input from the keyboard would run something like this:
#include <stdio.h>
#include <stdlib.h>
#define MAXSTRINGSIZE 128
int main(void)
{
char array[2][MAXSTRINGSIZE];
int i;
void *result;
for (i = 0; i < 2; i++)
{
printf("Input String %d: ", i);
result = fgets(&array[i][0], MAXSTRINGSIZE, stdin);
if (result == NULL) exit(1);
}
printf("String 1: %s\nString 2: %s\n", &array[0][0], &array[1][0]);
exit(0);
}
That compiles and runs correctly on my system. The only issue with fgets though is that is retains the newline character \n in the string. So if you don't want that, you will need to remove it. As for the *FILE parameter, stdin is a predefined *FILE structure that indicates standard input, or file descriptor 0. There are also stdout for standard output (file descriptor 1) and a stderr for error messages and diagnostics (file descriptor 2). The file descriptor numbers correspond to the ones used in a shell like so:
$$$-> cat somefile > someotherfile 2>&1
What that does is take outfile of file descriptor 2 and redirect it to 1 with 1 in turn being redirected to a file. In addition, I am using the & operator because we are addressing parts of an array, and the functions in question (fgets, printf) require pointers. As for the result, the man page for gets and fgets states the following:
RETURN VALUES
Upon successful completion, fgets() and gets() return a pointer to the string. If end-of-file occurs before any characters are read,
they return NULL and the buffer contents remain unchanged. If an
error occurs, they return NULL and the buffer contents are
indeterminate. The fgets() and gets() functions do not distinguish
between end-of-file and error, and callers must use feof(3) and
ferror(3) to determine which occurred.
So to make your code more robust, if you get a NULL result, you need to check for errors using ferror or end of file using feof and respond approperiately. Furthermore, never EVER use gets. The only way that you can use it securely is that you have to have the ability to see into the future, which clearly nobody can do so it cannot be used securely. It will just open you up for a buffer overflow attack.
this is my first question in this site, and I've just started programming, please be patient with me.
I'm having some trouble with this code to read strings and intergers from a file, they are separated by a semicolon ";" and it starts with the number of lines. The file is something like this:
13;
A;15;B;1;0;0;0;
A;9;C;0;3;2;0;
A;9;D;0;4;0;2;
A;3;E;2;3;2;0;
A;7;F;5;5;3;1;
A;5;G;5;7;6;0;
A;13;H;0;0;0;0;
A;1;I;8;1;0;0;
A;1;J;2;2;1;0;
A;6;K;7;3;2;0;
A;5;L;2;4;3;0;
A;12;AA;0;3;2;0;
A;9;BA;0;1;0;0;
What I tried to do was to create a function that would receive a file pointer (fp) and the number of lines that was read in the main function. It would read the file and save the intergers and strings in matrices :
#include<stdio.h>
#include<stdlib.h>
char timesjogos[100][2][100];
int golsjogos[100][3];
int faltasjogos[100][3];
int camajogos[100][3];
int cverjogos[100][3];
int ReadGames(FILE *caminho,int njogos){
printf("starting to read jogos.\n");
int i=0;
while(fscanf(caminho, " %[^;];%d[^;];%[^;];%d[^;];%d[^;];%d[^;];%d[^;];",
timesjogos[i][0], &golsjogos[i][0], timesjogos[i][1], &golsjogos[i][1],
&faltasjogos[i][0], &camajogos[i][0], &cverjogos[i][0]) == 7)
{
if(i < njogos)
i++;
else
break;
}
}
int main()
{
FILE *fp;
int nbets;
fp = fopen("jogos.txt", "r");
if (!fp){
printf ("Error trying to open file.");
}
fscanf(fp, " %d[^;];", &nbets);
ReadGames(fp, nbets);
}
My doubts are about the %[^;]; I used to read each string up to the ; , should I use %d[^;] for the intergers? What is the correct way to do it?
Also, I'm using global variables to save the information read, the problem is that they can be not large enough to save huge amounts of lines (my professor made a 24180 lines file to test our codes). I was thinking about using the number of lines it gives in the first line to make pre-sized matrices inside the function, but how can I return or save it after the function ends?
I'm sorry for the huge code, but I wanted to show all the details. I would be very thankful for your more experienced help :D
The %[^;] notation reads a string consisting of any number of non-semicolons. The parsing stops when a semicolon is encountered. With numbers, the parsing stops at a semicolon anyway; the semicolon is not a part of the representation of a number.
Your use of %d[^;] means that fscanf() is looking for an integer (%d), then an open square bracket, caret, semicolon and close square bracket. These don't appear in the input, of course, so the scanning fails.
Therefore, your input loop should probably be:
while (fscanf(caminho, " %[^;];%d;%[^;];%d;%d;%d;%d;",
timesjogos[i][0], &golsjogos[i][0], timesjogos[i][1],
&golsjogos[i][1], &faltasjogos[i][0], &camajogos[i][0],
&cverjogos[i][0]) == 7)
{
...
}
You might prefer to specify a maximum length for the %[^;] conversion specifications; %99[^;] would be appropriate since the third dimension of timesjogos is 100. There's an off-by-one difference between the length specified and the length used (enshrined because of ancient history; it was that way before the first C standard, and the C standard codified existing practice).
#include <stdio.h>
#include <stdlib.h>
FILE *fptr;
main()
{
char fileLine[100];
fptr = fopen("C:\\Users\\user\\Desktop\\Summary.h", "r");
if (fptr != 0){
while (!feof(fptr)){
fgets(fileLine, 100, fptr); // << not specified like fileLine[1] ?
if (!feof(fptr)){
puts(fileLine); // The same thing ?
}
}
}
else
{
printf("\nErorr opening file.\n");
}
fclose(fptr);
return 0;
}
The tremendous pain here, why the array elements are not specified, and how the array holds the lines?
char fileLine[100];
This is not an array of lines, it's an array of characters. One char represents one character (or more precisely one byte). The declaration char fileLine[100] makes it an array of 100 characters. C doesn't have distinct types for strings and for arrays of characters: a string (such as the content of a line) is just an array of characters, with a null byte after the last character.
At each run through the loop, fileLine contains the line that is read by fgets. That string is printed out by puts. Each call to fgets overwrite the line that was previously stored in the string.
Note that since fgets retains the newline character that terminates each line, and puts adds a newline after printing the string, you will get double-spaced output. If a line is more than 99 characters long (strictly speaking, again, more than 99 bytes long), you'll get a line break after each block of 99 characters.
If you wanted to store all the lines, you'd need an array of strings, i.e. an array of arrays of characters.
char fileLines[42][100];
int i = 0;
while (!feof(fptr)) {
fgets(fileLines[i], 100, fptr);
++i;
}
/* i-1 lines have been read, from fileLines[0] to fileLines[i-2] */
The way you're using feof is quite awkward there. feof tells you whether the last attempt to read reached the end of the file, not whether the next attempt to read would reach the end of the file. For example, here, after the last line has been read, feof() is false (because the program doesn't know yet that this is the last line, it has to attempt to read more); then fgets runs again, and returns NULL because it couldn't read anything. Nonetheless i is incremeneted; and after that feof() returns false which terminates the loop. Thus i ends up being one plus the number of lines read.
While you can fix this here by decrementing i, the way that actually works even in real-life programs — and that also makes more sense — is to test the result of fgets. You know that you've reached the end of the file because fgets is unable to read a line.
char fileLines[42][100];
int i = 0;
while (fgets(fileLines[i], 100, fptr))
++i;
}
/* i lines have been read, from fileLines[0] to fileLines[i-1] */
(This is a toy example, real-life code would need dynamic memory management and error checks for long lines, too many lines, and read errors.)
The array of characters that is fileLine is treated as a string.
I'm learning C from K&R's "The C Programming Language" book. I'm doing the exercises specified in the book. I'm on exercise number 1.16, but I don't understand it.
Exercise 1.16:
Revise the main routine of the longest-line program so it will
correctly print the length of arbitrarily long input lines, and as
much as possible of the text.
My questions:
"...as much as possible of the text..." - is there some limitation on string length? Maybe in standard headers there's a variable with the max allowed value of string length?
"...the length of arbitrarily long input lines..." - but in the code MAXLINE is defined as 1000. It is limited size too. I see some solutions here, but in my opinion it is not solution decision, since on the former there is a restriction on length of a line (1000 characters).
Maybe I don't understood the task. My understanding is I must remove the 1000-character limitation.
It's a pretty early exercise in K&R, you're just supposed to do some minor changes to the code, not a total redesign of the code.
"...as much as possible of the text..."
is up to you to interpret. I'd do it by printing what's stored in the longest buffer. i.e. print out up to 1000 characters of the line. Again, it's an early exercise, with little introduction to dynamically allocated memory yet. And at the time K&R was written, storing away arbitrarily long text lines wasn't as feasible as it is today.
"...the length of arbitrarily long input lines..."
Is a hard requirement. You're supposed to find the correct length no matter how long it is (at least within the bounds of an int. )
One way to solve this problem is:
After the call to getline(), check if the last character read into the line buffer is a newline ('\n')
If it is, you read a complete line. The len variable is the correct length of the line(the return value of getline(), and no special consideration is needed compared to to original code.
If it is not , you did not read the entire line, and need to hunt for the end of this line. You add a while loop, calling getchar() until it returns a newline (or EOF), and count the number of characters you read in that loop. Just do len++ to count.
When the while loop is done, the new len is now the actual length of the line, but our buffer just has the first 999 characters of it.
As before, you store away (the copy() function call) the current line buffer (max 1000 chars) if this line is the longest so far.
When you're done, you print out the stored line as before (the longest buffer) and the max variable for the length.
Due to the above mentioned while loop that max length is now correct.
If the longest line indeed was longer than 1000 chars. you at least print out those first 999 chars - which is "as much as possible".
I'll not spoil it and post the code you need to accomplish this, but it is just 6 lines of code that you need to add to the longest-line program of exercise 1-16.
On modern machines "as much as possible of the text" is likely to be all of the text, thanks to automatically line-wrapping terminal programs. That book was written when teletype terminals were still in use. There is no limitation on string length other than perhaps memory limitations of the machine you're working on.
They're expecting you to add some kind of loop to read characters and look for newlines rather than assuming that a read into the MAXLINE sized buffer is going to contain a newline for sure.
here is my version:
int getline(char s[],int lim)
{
int c,i;
for(i=0;i<lim-1&&(c=getchar())!=EOF&&c!='\n';++i)
s[i]=c;
if(c=='\n')
{
s[i]=c;
++i;
}
if(c!=EOF)
{
while((c=getchar())!=EOF&&c!='\n')
i++;
}
s[i]='\0';
return i;
}
#define MAXLINE 1000
int len;
int max;
char line[MAXLINE];
char longest[MAXLINE];
max=0;
while((len=getline(line,MAXLINE))>1)
{
if(len>max)
{
max=len;
copy(longest,line);
}
}
if(max>0)
{
printf("%d:%s",max,longest);
}
return 0;
for some unknown reasons ,the example code doesn't work in my pc
particularly,when the condition is 'len>0',the loop won't end
i think the main reason is that when you type nothing,but you still have to press enter,so it is received as '\n',and the len is 1;
i think it satisfy the requirement that print the length of arbitrarily long input lines, and as much as possible of the text.
And it works like this
#include
main()
{
long tlength = 0;
short input, llength = 1;
while (llength > 0) {
llength = 0;
while ((input = getchar()) != EOF) {
++llength;
if (input == '\n')
break;
}
tlength = tlength + llength;
printf("\nLength of just above line : %5d\n\n", llength);
}
printf("\n\tLength of entire text : %8ld\n", tlength);
return 0;
}
According to me, This question only wants the length of each arbitrarily line + At last the length of entire text.
Try to run this code and tell me is it correct according to question because i too confuse in this problem.
I want to offer that this exercise actually makes more sense if imagine that the limit of the number of characters you can copy is very small -- say, 100 characters -- and that your program is supposed to judge between lines that are longer than that limit.
(If you actually change the limit so that it's very small, the code becomes easier to test: if it picks out the first line that hits that small limit, you'll know your code isn't working, whereas if it returns the first however-many characters of the longest line, it's working.)
Keep the part of the code that copies and counts characters until it hits a newline or EOF or the line-size-limit. Add code that picks up where this counting and copying leaves off, and which will keep counting even after the copying has stopped, so long as getchar() still hasn't returned an EOF or a newline.
My solution: just below the call to getLine
if ( line[len-1] != '\n' && line[len-1] != EOF) //if end of line or file wasnt found after max length
{
int c;
while ( ( c = getchar() ) != '\n' && c != EOF )
len++; //keep counting length until end of line or file is found
}
to test it, change MAXLINE to 25