C - print file using system calls? - c

I'm trying to get aquainted with system calls and C. I'm trying to read a file and write all the contents to the command line. I'm trying
int handle = open("./test.txt", O_RDONLY, O_TEXT);
char buf[1];
lseek(handle, 0, SEEK_SET);
while (0 != read(handle, buf, 1)) {
printf(*buf);
}
This ALMOST works, except that it adds some gibberish characters after each character read from the file. For example if the file contains asd asd this writes a:_s:_d:_ :_a:_s:_d to the console. Any idea why? How can I fix it?

You code should produce warnings on most modern compilers. Because printf() doesn't accept a char. Since you are reading the file char by char, you can instead use putchar() to print on the stdout.
while (read(handle, buf, 1) == 1) {
putchar(buf[0]);
}

Every string has to end with the \0 (null) character.
So try to make your buffer size 2, and just before printf do buf[1] = '\0';
In general when you read wcnt (type ssize_t) number of chars you do buf[wcnt] = '\0';
Also your printf is not syntaxed correctly safely!
printf("%s", buf);
Edit: As mentioned in other answers and comments (I will not add it since I did not propose it first), you can just print a char in this case.

Related

Errorneous output while reading File in C

I am trying to write a string to a file and then read the string and output the string written into the file.
For example
INPUT (Input Name)
FalconHawk
OUTPUT
Hi FalconHawk! Have a great day!
My code is:
#include<stdio.h>
void main(){
char n[10],r[1000];
FILE *fptr,*fpt;
scanf("%s",n); //Input name
fptr=fopen("welcome.txt","w");
fprintf(fptr,"%s",n); //Write to file
fclose(fptr);
fpt=fopen("welcome.txt","r");
fscanf(fpt,"%s",r);
printf("Hi %s! Have a good day.",r); //Output file content
fclose(fpt);
}
But because of some reason I am getting an output like
INPUT (Input Name)
FalconHawk
OUTPUT
HiHi FalconHawk! Have a great day! //"Hi" is getting printed two times
On replacing "Hi" with "Welcome" I am getting an output like
OUTPUT
WelcomeWelcome FalconHawk! Have a great day! //"Welcome" is getting printed two times.
What is causing this issue?
Your buffer is too small and there's no room for the terminating null byte, therefore, your code invokes undefined behavior. If you want to read 10 characters, then this is how you should do it
char input[11];
if (scanf("%10s", input) == 1) {
// Safely use `input' here
}
And if you want to read an entire line of text from stdin then use fgets() instead
if (fgets(input, sizeof input, stdin) != NULL) {
// Safely use `input' here
}
Strings in c always need an extra byte of space to store the terminating '\0', read a basic tutorial on strings in c to learn how they work and how to treat them.

Using fread() to parse data through a file and stdin

I am trying to write an algorithm that takes input from a file and builds what is called an "s1 record". (The functionality of this function is not important) Depending on the command line arguments, the program will set the inputFile to the specified file, or stdin if no file is provided.
The algorithm needs to be structured in a way that can handle both file patterns.
The idea of this is to take FILE* data and read it into a buffer of size 16 bytes. Every 16 bytes of data, an s1 record will be built. As long as there are 16 bytes to read then it works fine and dandy. Once there is a line with less than 16 bytes, it doesn't create an s1 record.
Ive tested the output and these are some of the things I noticed:
When I run the program using "stdin", I am prompted for user input. I enter 20 characters (which should print 16 in 1 srecord, and 4 in another) and my output is as follows:
12345678901234567890
Buffer: 1234567890123456
S113000031323334353637383930313233343536AA
When I run the program using a file (record.dat) with one single line with the characters of the alphabet on it, I get this:
Buffer: ABCDEFGHIJKLMNOP
Buffer: QRSTUVWXYZKLMNOP
This is not valid either, as it prints the "KLMNOP" at the end of the line as well.
My question is: How can I structure this to accept the input from either a file or stdin using the same algorithm, and what exactly am I doing wrong in my algorithm? I have tried providing all the useful information I can, and can specify more detail if requested. Below is the code for the algorithm I am trying to write.
inputFile is set to stdin if no file is specified
char buffer[kMaxLineSize + 1] = { '\0' };
char byte = 0;
int count = 1;
while((fread(buffer, 1, kMaxLineSize, inputFile)))
{
printf("%c", byte);
clearCRLF(buffer);
printf("Buffer: %s\n", buffer);
if(outputFormat == 1)
{
char s1Record[kMaxSRecordSize] = { 0 };
buildS1Record(addressField, s1Record, buffer);
fprintf(outputFile, "%s\n", s1Record);
addressField += strlen(buffer);
s1Count++;
}
else
{
char asmRecord[kMaxASMRecordSize] = { 0 };
buildAssemblyRecord(asmRecord, buffer);
fprintf(outputFile, "%s\n", asmRecord);
}
}
I'll try to combine the comments in this answer.
But first, what you call an s1 "record" is not a record. It is a string of maximum 16 characters and a terminating null character. A record, in my understanding, is a struct with fields of possibly different types, one of which could be a string.
The code fixes are as follows:
char buffer[kMaxLineSize + 1] = { '\0' };
int len;
while (len=fread(buffer, 1, kMaxLineSize, inputFile))
{
...
char s1Record[kMaxSRecordSize] = { 0 };
buildS1Record(addressField, s1Record, buffer, len);
so you pass the length read to the function. Now it can copy the characters read and terminate with a '\0' character. Note also that there can be a discrepancy between kMaxLineSize and kMaxSRecordSize: they must be the same size (plus 1 for \0), so better use a single variable.
I hope this late answer can still be of use to you.

C string disappears along with newline

I'm new to C and stackoverflow, so pardon me if my question is silly or a duplicate.
So i tried to read some lines of string (and integers) from a .txt files and store it into an array of tuples. The strings read from the file seems to contain '\n' everytime, so i use strcspn() to remove it.
FILE* f = fopen("board.txt","r");
int x;
size_t size = 30;
char *buffer;
for (i=1;i<=32;i++)
{
buffer = (char *)malloc(size);
x = getline(&buffer,&size,f);
buffer[strcspn(buffer,"\n")] = 0;
A[i].name = buffer;
buffer = (char *)malloc(size);
x = getline(&buffer,&size,f);
buffer[strcspn(buffer,"\n")] = 0;
A[i].type = buffer;
buffer = (char *)malloc(size);
x = getline(&buffer,&size,f);
A[i].price = atoi(buffer);
}
for (i=1;i<=32;i++)
printf("%s ",A[i].name);
for (i=1;i<=32;i++)
printf("%s ",A[i].type);
However, when i tried the code above, the printf failed to print anything. But then when i tried to use \n in the printf ( printf("%s\n",A[i].type); ) it worked just fine. It seems like the strings completely disappear when i remove the "\n", and then come back only when i put '\n' as i print it.
Can someone explain what is wrong in the code? Or is it a library problem? Thank you in advance.
Edit : So to explain it a little further, i need those string (name and type) to be printed into 'boxes' to form a kind of board game, so i think bringing newline would cause a lot of trouble later on.
This is the correct behavior. The '\n' causes the OS to flush the buffer used for prints, so that it appears on stdout. Without a '\n' the OS isn't forced to write your print to stdout yet.
printf belongs to the Standard I/O library, it is a line buffered function. So when this function is called, it stores characters in a buffer and the only way to get the output (to stdout) is to flush with a newline character. This is the way it was designed so as to maintain a minimal number of system calls as possible.
Try eliminating this,
buffer[strcspn(buffer,"\n")] = 0;

`read()` system call in C does not read bytes

I'm trying to read characters from a file and count the frequency of a particular word in a file using system calls, but the behavior of one of my read() calls is confusing me. This is the code that I've written:
int counter, seekError,readVal;
counter = 0;
char c[1];
char *string = "word";
readVal = read(fd,c,1);
while (readVal != 0){ // While not the end of the file
if(c[0] == string[0]) { // Match the first character
seekError = lseek(fd,-1,SEEK_CUR); // After we find a matching character, rewind to capture the entire word
char buffer[strlen(string)+1];
buffer[strlen(string)] = '\0';
readVal = read(fd,buffer,strlen(string)); // This read() does not put anything into the buffer
if(strcmp(lowerCase(buffer),string) == 0)
counter++;
lseek(fd,-(strlen(string)-1),SEEK_CUR); // go back to the next character
}
readVal = read(fd,c,1);
}
In all the read calls that I use, I am able to read characters with no problem from my file. However, the readVal = read(fd,buffer,strlen9string)); line never puts anything into buffer, no matter how I try to read the characters. Is there anything going on behind the scenes that would explain this kind of behavior? I've tried running this code on different machines as well, but I still get nothing in buffer at that line.
It shouldn't be necessary to cast -1 into the off_t type. It looks like your real bug is that you didn't include <unistd.h> so lseek wasn't properly declared when you used it. Either that or there's a serious bug in your system's implementation of lseek.
The problem here was that the -1 in the seekError = lseek(fd,-1,SEEK_CUR); line was being interpreted as 4294967295. After casting it into the off_t type, the system interpreted the offset as -1 instead of the large number.
So the corrected line is: seekError = lseek(fd,(off_t)-1,SEEK_CUR);

Comparing strings in C

I have a program that reads student names and grades line by line from a .txt file using fgets and a buffer declared as:
char buffer[1024];
Now the file should end with the string "end" on a line all by itself.
How do I tell a while loop to terminate when buffer == "end"?
I tried using strcmp but it segfaults for some reason.
To simply answer your question, strcmp actually is the function you're looking for:
#include <string.h>
if(!strcmp(line, "end\n") || !strcmp(line, "end\r\n"))
break;
or similar should do the trick. Note the ! in front of strcmp as strcmp returns 0 (i.e. false) if the strings match. But I guess you already know that since you've already mentioned strcmp in your question.
On the segfault issue: Are you sure none of the pointers you pass to strcmp are NULL? Most C standard libraries don't do any error checking here and will run into segfaults when trying to read the memory at *(0).
Another possible issue that pops into my mind is that using strcmp will of course only work if you've already split your buffer into an array of single strings. strtok_r is probably most suited for this task (Altough quite tricky to use).
Why not just use formatted IO when the format of the text in the file is fixed and use !EOF for looping?
For example:
while(fp!=EOF)
{ fscanf(fp,"%s %s %d",name,grades, &marks);
printf("Name: %s\tGrade: %s\t Marks: %d\n",name,grade,marks);
}
This would automatically detect the end of file, which would also remove the condition of having a string 'end' in the text file.
char *fgets(char *restrict s, int n, FILE *restrict stream);
The fgets() function shall read bytes from stream into the array pointed to by s, until n-1 bytes are read, or a is read and transferred to s, or an end-of-file condition is encountered. The string is then terminated with a null byte.
so, when you read string "end", the element in buffer should be {'e', 'n', 'd', '\n', '\0'}, you can using strcmp as follows:
size_t len = strlen(buffer);
if (buffer[len - 1] == '\n')
{
buffer[len - 1] == '\0';
}
if (strcmp(buffer, "end") == 0)
{
//end
}
or
if (strncmp(buffer, "end", 3) == 0)
{
//end
}
Using strncmp(buffer, "end", 3) to compare the first three characters along with if(3 == strlen(buffer) to make sure end does not start the line, should solve the problem.

Resources