Fread/fwrite unexpected behavior - fwrite

I have created a file 'meta.dat' in my current directory and want the code below to give me this output
The character B
Number of items read 1
int main() {
FILE* fp = fopen("meta.dat", "wb");
char j = 'B';
fwrite(&j, sizeof(j), 1, fp);
fclose(fp);
FILE* fp1 = fopen("meta.dat", "rb");
char i = '\0';
int n = fread(&i, sizeof(i), 1, fp1);
printf("The character %c\n", &i);
printf("Number of items read %d\n", &n);
}
However what I get is this output in my console (I use Windows):
The character &
Number of items read 6422304
What's wrong with the code? And what's happening behind the scenes, why am I seeing this strange output?

Related

Writing value 0 to a binary file

I am generating a binary file from a SystemVerilog simulation environment. Currently, I'm doing the following:
module main;
byte arr[] = {0,32, 65, 66, 67};
initial begin
int fh=$fopen("/home/hagain/tmp/h.bin","w");
for (int idx=0; idx<arr.size; idx++) begin //{
$fwrite(fh, "%0s", arr[idx]);
end //}
$fclose(fh);
$system("xxd /home/hagain/tmp/h.bin | tee /home/hagain/tmp/h.txt");
end
endmodule : main
The problem is, that when b has the value of 0, nothing is written to the file. xxd output is:
0000000: 2041 4243 ABC
Same result when casting to string as follows:
$fwrite(fh, string'(arr[idx]));
I tried to change the write command to:
$fwrite(fh, $sformatf("%0c", arr[idx]));
And then I got the same value for the first two bytes ('d0 and 'd32):
0000000: 2020 4142 43 ABC
Any idea on how to generate this binary file?
You cannot have a null(0) character in the middle of a string, it is used to terminate the string.
You should use the %u format specifier for unformated data.
module main;
byte arr[] = {0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9};
int fh, c, tmp;
initial begin
fh = $fopen("h.bin","wb");
for (int idx=0; idx<arr.size; idx+=4) begin
tmp = {<<8{arr[idx+:4]}};
$fwrite(fh, "%u", tmp);
end
$fclose(fh);
fh = $fopen("h.bin","r");
while ((c = $fgetc(fh)) != -1)
$write("%d ",c[7:0]);
$display;
end
endmodule : main
Note that %u writes a 32-bit value in least-significant bytes first order, so I reversed the bytes being written with the streaming operator {<<8{arr[idx+:4]}}. If the number of bytes is not divisible by 4, it will just pad the file with null bytes.
If you need the exact number of bytes, the you will have to use some DPI C code
#include <stdio.h>
#include "svdpi.h"
void DPI_fwrite(const char* filename,
const svOpenArrayHandle buffer){
int size = svSize(buffer,1);
char *buf = (char *)svGetArrayPtr(buffer);
FILE *fp = fopen(filename,"wb");
fwrite(buf,1,size,fp);
}
And then import it with
import "DPI-C" function void DPI_fwrite(input string filename, byte buffer[]);
...
DPI_fwrite("filename", arr);

strncpy functions produces wrong file names

I am new in C and writing a code to help my data analysis. Part of it opens predetermined files.
This piece of code is giving me problems and I cannot understand why.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLOGGERS 26
// Declare the input files
char inputfile[];
char inputfile_hum[MAXLOGGERS][8];
// Declare the output files
char newfile[];
char newfile_hum[MAXLOGGERS][8];
int main()
{
int n = 2;
while (n > MAXLOGGERS)
{
printf("n error, n must be < %d: ", MAXLOGGERS);
scanf("%d", &n);
}
// Initialize the input and output file names
strncpy(inputfile_hum[1], "Ahum.csv", 8);
strncpy(inputfile_hum[2], "Bhum.csv", 8);
strncpy(newfile_hum[1], "Ahum.txt", 8);
strncpy(newfile_hum[2], "Bhum.txt", 8);
for (int i = 1; i < n + 1; i++)
{
strncpy(inputfile, inputfile_hum[i], 8);
FILE* file1 = fopen(inputfile, "r");
// Safety check
while (file1 == NULL)
{
printf("\nError: %s == NULL\n", inputfile);
printf("\nPress enter to exit:");
getchar();
return 0;
}
strncpy(newfile, newfile_hum[i], 8);
FILE* file2 = fopen(newfile, "w");
// Safety check
if (file2 == NULL)
{
printf("Error: file2 == NULL\n");
getchar();
return 0;
}
for (int c = fgetc(file1); c != EOF; c = fgetc(file1))
{
fprintf(file2, "%c", c);
}
fclose(file1);
fclose(file2);
}
// system("Ahum.txt");
// system("Bhum.txt");
}
This code produces two files but instead of the names:
Ahum.txt
Bhum.txt
the files are named:
Ahum.txtv
Bhum.txtv
The reason I am using strncpy in the for loop is because n will actually be inputted by the user later.
I see at least three problems here.
The first problem is that your character array is too small for your strings.
"ahum.txt", etc. will need to take nine characters. Eight for the actual text plus one more for the null terminating character.
The second problem is that you have declared the character arrays "newfile" and "inputfile" as empty arrays. These also need to be a number able to contain the strings (at least 9).
You're lucky to have not had a crash from overwriting memory out the program space.
The third and final problem is your use of strcpy().
strncpy(dest, src, n) will copy n characters from src to dest, but it won't copy final null terminator character if n is equal or less than size of the src string.
From strncpy() manpage: https://linux.die.net/man/3/strncpy
The strncpy() function ... at most n bytes of src are copied.
Warning: If there is no null byte among the first n bytes of src,
the string placed in dest will not be null-terminated.
Normally what you would want to do is have "n" be the size of the destination buffer minus 1 to allow for the null character.
For example:
strncpy(dest, src, sizeof(dest) - 1); // assuming dest is char array
There are a couple of problems with your code.
inputfile_hum, newfile_hum, need to be to be one char bigger for the trailing '\0' on strings.
char inputfile_hum[MAXLOGGERS][9];
...
char newfile_hum[MAXLOGGERS][9];
strncpy expects the first argument to be a char * region big enough to hold the expected results, so inputfile[] and outputfile[] need to be declared:
char inputfile[9];
char outputfile[9];

scanf() value ignored after reading a char

Got stuck on an problem getting more familiar with C(++) on Hackerrank. Using scanf() I want to read a line with a bunch of different values.
The issue is that the value after char is ignored. Read solutions to this was to add a space before the char, but I've tried running a scanf() on a seperate line per value, and only keeping the space infront of the char but still the problem persisted.
The lesson to be learned seems to be using scanf() and not any other type of input method. So no reading with cin or fscanf(). And reason for this being one can read all kinds of values on the same line. So I don't want to make more than this one line for reading the input either.
#include <iostream>
#include <cstdio>
using namespace std;
int main() {
int i;
long l;
long long ll;
char c;
float f;
double d;
/** Read "3 444 12345678912345 a 334.23 14049.30493" from stdin */
scanf("%i %ld %lld %c %f %lf", &i, &l, &ll, &c, &f, &d);
printf("%d\n", i); // 3, as expected
printf("%ld\n", l); // 444 also as expected
printf("%lld\n", ll); // 12345678912345 ...
printf("%c\n", c); // 'a'
printf("%f\n", d); // 14049.30493 ?? It should be: 334.23
printf("%lf\n", d); // 14049.30493 but this time as it should be.
return 0;
}
scanf("%i %ld %lld %c %f %lf", &i, &l, &ll, &c, &f, &d);
^
!F! D
printf("%d\n", i);
printf("%ld\n", l);
printf("%lld\n", ll);
printf("%c\n", c);
printf("%f\n", d); // < D!
printf("%lf\n", d); // < D!
You are printing the d variable twice and never f.

How to let fscanf stop reading after a new line

#include <stdio.h>
#define MAX 1000
int line_counter (FILE *file, char buf[]);
int main(int argc, char *argv[]) {
FILE *ptr_file;
char buf[MAX];
ptr_file = fopen("alice-eg.txt", "r");
if (!ptr_file) {
return 1;
}
int count = 0;
while (fscanf(ptr_file, "%s", buf) == 1) {
printf("%s", buf);
if (buf == '\n') {
return count;
}
else {
count += 1;
}
}
printf("The number of words in this line is: %d", count);
return 0;
}
I want to do something along the lines of this but I have no idea how to make it work as the buf is just a pointer to an array of letters (correct me if I'm wrong I just started with C and my understanding of pointers is still quite bad).
fscanf write the line from the file (separated by ENTER) to the buff array and so if it will read an empty line buff[0] = '\n' so that should be your condition.
Secondly:
while (fscanf(ptr_file, "%s", buf) == 1)
Is wrong since fscanf returns the number of read character and so for the line "abcd" form the file it will return 4 and your loop will stop right away instead of reading the entire file and so your condition should be:
while (fscanf(ptr_file, "%s", buf) != EOF)
since fscanf will return EOF when it will reach the end of the file

How to search a specific word in lex given a input file?

I am very new to lex. I am trying to develop a parser to search a count of specific word in an given input file...
My code is
%{
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int lnum = 1, fresult = 0, cc=0, wc=0, lc=0, bc=0, sc=0, nc=0, tc=0, result;
char temp[20], str[20], fname[20];
FILE *fp;
#undef yywrap
%}
digit[0-9]+
word [a-zA-Z]+
eol [\n]
blank [ ]
tab [\t]
result [word]
%%
{result} {
if((strstr(temp, str)) != 0)
{
printf(" A match found on line: %d\n", lnum);
fresult++;
wc++;
cc+=yyleng;
}
lnum++;
if(fresult == 0)
{
printf(" Match not found\n");
}
}
{digit} {nc++;}
{word} {wc++; cc+=yyleng;}
{tab} {tc++;}
{blank} {bc++;}
{eol} {lc++;}
. sc++;
%%
int main(int argc, char *argv[])
{
strcpy(fname,argv[1]);
strcpy(str,argv[2]);
fp=fopen(fname,"r+");
yyin=fp;
yylex();
printf(" Total count of the word is :%d\n", fresult);
printf(" Character Count = %d\n", cc);
printf(" Number Count = %d\n", nc);
printf(" Word Count = %d\n", wc);
printf(" Line Count = %d\n", lc);
printf(" Special Character Count = %d\n", sc);
printf(" Blank Count = %d\n", bc);
printf(" Tab Count = %d\n", tc);
return(0);
}
int yywrap()
{
return -1;
}
The word count and others are working perfectly.... But the word search is taking the input but not given the specific count...... How can I improve the code?
Should I need to add anything?
Thanks in Advance...... :)
I have made some changes to your code to help you in the right direction. First, I created a variable to keep track of whether a match is found or not.
Secondly, I am not using strstr() anymore and instead I am using strcmp() because you want to match a word to a word not a word within a sentence and we do not need a pointer returned. strcmp() is nice because we just get an integer.
I see what you were trying to do with result [word] however, as you found out, this will not work. This section of the Flex file is known as the rules section. Here you use the regular expressions that you defined in the above section (definitions) to tell Flex what to do when a rule is matched.
As you can see, I have deleted all occurrences of result[word] - as this will not work. In the rules section, I also deleted the result definition because we no longer have a rule to match it. However, I keep the code for the result definitions and simply apply it to the word definition.
The last major change is adding the <<EOF>> rule which is a special rule that tells Flex what to do when it has encountered the end of the file. In our case, if the match variable is not 1, then we have not found a match and we would like to print this to the screen. We also need to call yyterminate() (definition at the bottom of the page) to stop the lexical analyzer.
Below is the updated code. I hope that helps!
%{
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int lnum = 1, fresult = 0, cc=0, wc=0, lc=0, bc=0, sc=0, nc=0, tc=0, result;
char temp[20], str[20], fname[20];
FILE *fp;
int match = 0;//For keeping track of matches
#undef yywrap
%}
/*Rules*/
digit [0-9]+
word [a-zA-Z]+
eol [\n]
blank [ ]
tab [\t]
/*Definitions*/
%%
{digit} {
nc++;
}
{tab} {
tc++;
}
{blank} {
bc++;
}
{eol} {
lc++;
}
{word} {
if((strcmp(yytext, str)) == 0)//We found a match
{
printf("\n A match found on line: %d\n", lnum);
fresult++;
wc++;
cc+=yyleng;
match = 1;//We have a match
}
else //We found a word, but it was not a match
{
wc++;
}
}
. {
sc++;
}
<<EOF>> {
if(!match)
{
printf(" Match not found\n");
}
yyterminate();
}
%%
int main(int argc, char *argv[])
{
strcpy(fname,argv[1]);
strcpy(str,argv[2]);
fp = fopen(fname,"r+");
yyin = fp;
yylex();
printf("\n\n Total count of the word is :%d\n", fresult);
printf(" Character Count = %d\n", cc);
printf(" Number Count = %d\n", nc);
printf(" Word Count = %d\n", wc);
printf(" Line Count = %d\n", lc);
printf(" Special Character Count = %d\n", sc);
printf(" Blank Count = %d\n", bc);
printf(" Tab Count = %d\n", tc);
fclose(fp);
return(0);
}
int yywrap()
{
return 1;
}
{result} {
if((strstr(temp, str)) != 0)
result [word]
Result is a regex for the characters 'w', 'o', 'r', 'd', which is not what you want. You probably want to match on {word}. In addition, temp will always be null - I think you want to use yytext instead.