Loop over stdin in C - c

I am trying to loop over stdin, but since we cannot know the length of stdin, I am not sure how to create the loop or what condition to use in it.
Basically my program will be piped in some data. Each line in the data contains 10 characters of data, followed by a line break (So 11 characters per line)
In pseudocode, what I am trying to accomplish is:
while stdin has data:
read 11 characters from stdin
save 10 of those characters in an array
run some code processing the data
endwhile
Each loop of the while loop rewrites the data into the same 10 bytes of data.
So far, I have figured out that
char temp[11];
read(0,temp,10);
temp[10]='\0';
printf("%s",temp);
will take the first 11 characters from stdin,and save it. The printf will later be replaced by more code that analyzes the data. But I don't know how to encapsulate this functionality in a loop that will process all my data from stdin.
I have tried
while(!feof(stdin)){
char temp[11];
read(0,temp,11);
temp[10]='\0';
printf("%s\n",temp);
}
but when this gets to the last line, it keeps repeatedly printing it out without terminating. Any guidance would be appreciated.

Since you mention line breaks, I assume your data is text. Here is one way, when you know the line lengths. fgets reads the newline too, but that is easily ignored. Instead of trying to use feof I simply check the return value from fgets.
#include <stdio.h>
int main(void) {
char str[16];
int i;
while(fgets(str, sizeof str, stdin) != NULL) { // reads newline too
i = 0;
while (str[i] >= ' ') { // shortcut to testing newline and nul
printf("%d ", str[i]); // print char value
i++;
}
printf ("\n");
str[i] = '\0'; // truncate the array
}
return 0;
}
Program session (ended by Ctrl-Z in Windows console, Ctrl-D in Linux)
qwertyuiop
113 119 101 114 116 121 117 105 111 112
asdfghjkl;
97 115 100 102 103 104 106 107 108 59
zxcvbnm,./
122 120 99 118 98 110 109 44 46 47
^Z

Related

Read an image like a text, line by line

I have a text file that has a structure like:
P2
# CREATOR: GIMP PNM Filter Version 1.1
445 243
255
108
107
104
102
102
[...]
And i want to read this text file line by line. So i writed this code:
int main(void) {
char str[50];
FILE *fp;
fp = fopen("/home/user/Downloads/file.pgm", "r");
if(fp == NULL)
{
printf("Error opening file\n");
exit(1);
}
printf("Testing fgets() function: \n\n");
printf("Reading contents of myfile.txt: \n\n");
while( fgets(str, 30, fp) != NULL )
{
puts(str);
}
fclose(fp);
return 0;
}
However, it gives a strange output. And i don't know where is the error. The code seems ok. What do you think ?
Execution :
You're limiting the fgets to 30 chars, and the comment
# CREATOR: GIMP PNM Filter Version 1.1
is 38 characters.
it is simple fgets also return the \n when it is read (it is not discarded) and writing by puts you add an other \n after the print, so you have 2 \n creating an empty line
Replace puts(str); by fputs(stdout, str); and you will not have the empty lines
Note : the output doesn't correspond to the beginning of the file, may be its end ?
if I put
P2
# CREATOR: GIMP PNM Filter Version 1.1
445 243
255
108
107
104
102
102
in the file the execution gives :
pi#raspberrypi:/tmp $ ./a.out
Testing fgets() function:
Reading contents of myfile.txt:
P2
# CREATOR: GIMP PNM Filter Ve
rsion 1.1
445 243
255
108
107
104
102
102
one line is cut because has more than 29 characters

Why does the file created using a text editor contain one byte more than expected?

I created a file like this
a v
bb
e
And I didn't press enter after typing e in the last line.
So there are four characters in the first line 'a',' ','v','\n'.
There are three characters in the second line 'b','b','\n'.
And there is one character in the last line 'e'.
So there are totally 8 characters in this file. But when I count the characters using the following C program:
#include<stdio.h>
/* count characters in input; 1st version */
int main()
{
long nc;
nc = 0;
while (getchar() != EOF) {
++nc;
}
printf("%ld\n", nc);
return 0;
}
It gave me 9. Even when I use wc command to count, it is still 9. Why?
There's reasoning in favor of having all lines terminated with a newline character:
Why should text files end with a newline?
And there are text editors that are set up to add a trailing newline character automatically (if not already there):
How to stop Gedit, Gvim, Vim, Nano from adding End-of-File newline char?
Probably that is why you observe the unexpected file size.
To inspect the actual content of such files, I like to use hexdump:
$ hexdump -C test
00000000 61 20 76 0a 62 62 0a 65 0a |a v.bb.e.|
00000009

How do I seek in stdin

Hello guys I need a help. I want to read from stdin by 16 bytes. Every byte I convert into hexadecimal form. Is there a way I can use read() function to read NOT from the beginning, but for example from the second byte? Also how can I know if I have read the whole stdin? - This way I could call this function in a cycle until I have read the whole stdin
This is a function I made:
void getHexLine()
{
int n = 16;
char buffer[n];
read(STDIN_FILENO, buffer, n);
buffer[n]='\0';
//printf("%08x", 0); hex number of first byte on line - not working yet
putchar(' ');
putchar(' ');
//converting every byte into hexadecimal
for (int i = 0;i < 16;i++ )
{
printf("%x", buffer[i]);
putchar(' ');
if (i == 7 || i == 15)
putchar(' ');
}
printf("|%s|\n", buffer);
}
The output should be like this but with an option to start from second byte for example.
[vcurda#localhost proj1]$ echo "Hello, world! This is my program." | ./proj1
48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21 20 54 68 |Hello, world! Th|
69 73 20 69 73 20 6d 79 20 70 72 6f 67 72 61 6d |is is my program|
This is a school project so I cant use malloc, scanf and <string.h>. I would be really glad if I get some help and sorry for my not very understandable english.
stdin is not seekable. You can read bytes in, but you can't rewind or fast forwards. EOF (-1) means end of input in stdin as with a regular file, but it's a bit of a looser concept if you are conducting an interactive dialogue with the user.
Basically stdin is line oriented, and it's best to use the pattern printf() prompt, enter whole line from user, printf() results if applicable and another prompt, read in whole line from user, and so on, at least at first until you get used to programming stdin.
To start from the second byte then becomes easy. Read in the whole line, then start from i = 1 instead of i = 0 as you parse it.
Is there a way I can use read() function to read NOT from the
beginning, but for example from the second byte?
Most universally, you can simply ignore the read-in bytes you're not interested in.
Sometimes you will be able to lseek, e.g. if you run your program with
a regular file set to its STDIN as in:
./a.out < /etc/passwd
but lseek will fail on STDINs that are terminals, pipes, character devices, or sockets.
how can I know if I have read the whole stdin?
read will return 0 at the end of the file.
Consult the manual pages for more information.
Generally, you should check your return codes and account for short reads. Your function should probably return an int so that it has a way to communicate a possible IO error.

fgetc dropping characters when reading 2d pixel map with for loop

I am working on inputting a 2d pixel array from a PPM file with the one I am testing being of width and length 5. Also I am aware that in a ppm file that is rgb it has 3 color values not just one. I had forgotten that before I wrote this code, but the problem still persists even with the update to it and the problem still exists in the same way. I have simplified the problem to just the array as to isolate the problem. From what I can tell this seems to be both dropping characters and replacing some with new line characters as well. Any insight into why this is happening would be greatly appreciated and if I forgot to add something I will update this as soon as I am aware.
#include <stdio.h>
int main(int args, char *argv[]) {
int w = 5, h = 5;
FILE *f = fopen(argv[1], "rb");
int c = 'a';//I am setting this so as to avoid the off chance of c being defined as EOF
for(int i = 0; i < h && c != EOF; i++) {
for(int j = 0; j < w && (c = fgetc(f)) != EOF; j++) printf("%c", c);
fgetc(f);//To remove the '\n' character I am not using fgets because it stops at '\n' character and it is possible for a rgb value to be == to '\n'
printf("\n");
}
fclose(f);
return 0;
}
Test File I am using:
12345
abcde
12345
abcde
12345
Output I am getting:
12345
abcd
123
5
ab
de
1
Thanks in advance!
Edit: This is running on the windows 10 command prompt
The problem is that '\n' on a Windows machine actually ends up producing two characters, a carriage return (ASCII code 13) and a line feed (ASCII code 10). When you open a file in binary mode, those line endings are not translated back to a single character. You're only accounting for one of these characters, so you're getting off by a character on each line you read.
To illustrate this, replace your printf("%c", c);" with printf("%d ", c);. I get the following output:
49 50 51 52 53
10 97 98 99 100
13 10 49 50 51
53 13 10 97 98
100 101 13 10 49
You can see those 10s and 13s shifting through.
Now try adding a second fgetc(f); to eat the line feed and it will work much better. Keep in mind, however, that this only works on files with CRLF line endings. Port it to Linux or Mac and you will have more troubles.

Reading in a text file to be formatted and output (C programming)

I'm working a program for a class and it's proving much more difficult than I thought.
It's my very first experience with C, but I've had some experience with Java so I understand the general concepts.
My goal: read in a text file that has some formatting requirements contained within the file, store the file in an array, apply the formatting and output the formatted text to stdout.
The problem: reading in the file is easy, but I'm having trouble with the formatting and output.
The challenge:
--the input file will begin with ?width X, ?mrgn Y, or both (where X and Y are integers). these will always appear at the beginning of the file, and will each be on a separate line.
--the output must have the text formatted as per the formatting request (width, margin).
--additionally, there is a 3rd format command, ?fmt on/off, which can appear multiple times at any point throughout the text and will turn formatting on/off.
--just a few catches: if no ?width command appears, formatting is considered off and any ?margin commands are ignored.
--if a ?width command appears, formatting is considered on.
--the files can contain whitespace (as both tabs and spaces) which must be eliminated, but only when formatting is on.
--dynamic memory allocation is not allowed.
Easy for a first C program right? My professor is such a sweety.
I've been working on this code for hours (yes, I know it doesn't look like it) and I'm making little progress so if you feel like a challenge I would very much appreciate help of any kind. Thanks!
So far my code reads in the text file and formats the margin correctly. Can't seem to find a good way to eliminate whitespace (I believe tokenizing is the way to go) or do the word wrap when the length of the line is longer than the ?width command.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #define MAX_LINE_LEN 133 /* max 132 char per line plus one extra for the new line char
6 #define MAX_LINES 300 /* max 300 lines per input file */
7 #define MAX_CHARS 39900 /* max number of characters in the file */
8
9 /* Initializes array used to store lines read in from text
10 file as well as output array */
11 char input[MAX_LINE_LEN];
12 char buffer[MAX_CHARS];
13 char word_wrap[MAX_LINE_LEN];
14
15 /* Functions */
16 void parameters(char [], FILE *);
17
18 /* Variables */
19 int width = 0;
20 int margin = 0;
21
22 /*
23 argc is the count of input arguments
24 *argv is a pointer to the input arguments
25 */
26 int main (int argc, char *argv[])
27 {
28 /* Creates file pointer */
29 FILE *fp = fopen(argv[1], "r"); /* r for read */
30
31 if (!fp) /* Error checking */
32 {
33 printf("Error: Could not open file");
34 return 0;
35 }
36
37 /* Retrieves width and margin parameters from input file */
38 parameters(input, fp);
39
40 fclose(fp); /* Closes file stream */
41
42 return 0;
43 }
44
45 void parameters(char input[], FILE *fp)
46 {
47 /* Gets input file text line by line */
48 while (fgets (input, 133, fp) != NULL)
49 {
50 /* Creates a pointer to traverse array */
51 char *p = input;
52
53 /* Checks for width parameter read in from text file */
54 if (input[0] == '?' && input [1] == 'w')
55 {
56 strtok(input, " "); /* Eliminates first token '?width' */
57 width = atoi(strtok(NULL, " ")); /* Stores int value of ASCII token
58 p = NULL;
59 }
60
61 /* Checks for margin parameter read in from text file */
62 if (input[0] == '?' && input[1] == 'm')
63 {
64 strtok(input, " "); /* Eliminates first token '?mrgn' */
65 margin = atoi(strtok(NULL, " ")); /* Stores int value of ASCII token
66 p = NULL;
67 }
68
69 if (p != NULL) /* skips printing format tokens at beginning of file */
70 {
71 if (width == 0) /* no width command, formatting is off by default */
72 {
73 printf("%s", p); /* Prints unformatted line of text */
74 }
75 else /* formatting is on */
76 {
77 printf("%*s" "%s", margin, " ", p); /* Prints formatted line of text
78 }
79 }
80 }
81 }
82
And here's an example input file, along with its proper output:
?width 30
?mrgn 5
While there are enough characters here to
fill
at least one line, there is
plenty
of
white space which will cause
a bit of confusion to the reader, yet
the ?fmt off command means that
the original formatting of
the lines
must be preserved. In essence, the
command ?pgwdth is ignored.
Output:
While there are enough
characters here to fill
at least one line, there
is plenty of white space
which will cause a bit of
confusion to the reader,
yet the ?fmt off command means that
the original formatting of
the lines
must be preserved. In essence, the
command ?pgwdth is ignored.

Resources