Overwriting lines in file in C - c

I'm doing a project on filesystems on a university operating systems course, my C program should simulate a simple filesystem in a human-readable file, so the file should be based on lines, a line will be a "sector". I've learned, that lines must be of the same length to be overwritten, so I'll pad them with ascii zeroes till the end of the line and leave a certain amount of lines of ascii zeroes that can be filled later.
Now I'm making a test program to see if it works like I want it to, but it doesnt. The critical part of my code:
file = fopen("irasproba_tesztfajl.txt", "r+"); //it is previously loaded with 10 copies of the line I'll print later in reverse order
/* this finds the 3rd line */
int count = 0; //how much have we gone yet?
char c;
while(count != 2) {
if((c = fgetc(file)) == '\n') count++;
}
fflush(file);
fprintf(file, "- . , M N B V C X Y Í Ű Á É L K J H G F D S A Ú Ő P O I U Z T R E W Q Ó Ü Ö 9 8 7 6 5 4 3 2 1 0\n");
fflush(file);
fclose(file);
Now it does nothing, the file stays the same. What could be the problem?
Thank you.

From here,
When a file is opened with a "+"
option, you may both read and write on
it. However, you may not perform an
output operation immediately after an
input operation; you must perform an
intervening "rewind" or "fseek".
Similarly, you may not perform an
input operation immediately after an
output operation; you must perform an
intervening "rewind" or "fseek".
So you've achieved that with fflush, but in order to write to the desired location you need to fseek back. This is how I implemented it - could be better I guess:
/* this finds the 3rd line */
int count = 0; //how much have we gone yet?
char c;
int position_in_file;
while(count != 2) {
if((c = fgetc(file)) == '\n') count++;
}
// Store the position
position_in_file = ftell(file);
// Reposition it
fseek(file,position_in_file,SEEK_SET); // Or fseek(file,ftell(file),SEEK_SET);
fprintf(file, "- . , M N B V C X Y Í Ű Á É L K J H G F D S A Ú Ő P O I U Z T R E W Q Ó Ü Ö 9 8 7 6 5 4 3 2 1 0\n");
fclose(file);
Also, as has been commented, you should check if your file has been opened successfully, i.e. before reading/writing to file, check:
file = fopen("irasproba_tesztfajl.txt", "r+");
if(file == NULL)
{
printf("Unable to open file!");
exit(1);
}

Related

A histogram of the length of words in its input. exercise 1_13, k&r pdf

I have just started learnign to program, and I'm having troubles writing a program from k&r second edition pdf, to write a a program histogram of the length of words in its input I imagined my program would be something like:
(words number)
1 XXX
2 XXXXX
3 XX
4
5 X
12345 (charcacters number)
Here is the code I have done so far:
#include <stdio.h>
#define out 0
#define in 1
int main()
{
char X, nc;
int state, nw, i, x_count[10], c;
i = 0;
nc = 0;
nw = 1;
for (i = 0; i < 10; ++i)
x_count[i] = 0;
while ((c = getchar()) != EOF) {
if (state == in && c != '\b' && c != ' ' && c != '\t')
++nc;
else {
++nw;
state = out;
}
if (state == out) {
for (i = 0; i < nc; i++) {
x_count[i] = X;
}
}
state = in;
}
printf("%d: %c", nw, x_count[i]);
return 0;
}
As pointed out by #kaylum in the comment, the immediate problem that breaks the defined behavior of your code is your use of state before it has been assigned a value in:
if (state == in && ...
state is a variable declared with automatic storage duration. Until the variable state is explicitly assigned a value, its value is indeterminate. Using state while its value is indeterminate results in Undefined Behavior. See: C11 Standard - 6.7.9 Initialization(p10) and J.2 Undefined Behavior
Once you invoke Undefined Behavior in your code, the defined execution is over and your program can do anything between appearing to run correctly or SegFault. See: Undefined, unspecified and implementation-defined behavior
The simple fix is to initialize int state = out; to begin with. (you will start in the out state in order to ignore leading whitespace before the first word)
You have similar problems with your variable X which is not initialized and is used when its value is indeterminate in x_count[i] = X; Moreover, it is unclear what you intend to do with int X to begin with. It is clear from your desired output:
(words number)
1 XXX
2 XXXXX
3 XX
4
5 X
12345 (charcacters number)
That you want to output one 'X' per-character (to indicate the word length for your histogram), but there is no need to store anything in a variable X to do that, you simply need to output one character 'X' for each character in the word. Additionally your output of 4 does not make much sense being empty as your state-variable state should prevent counting empty words. You would never have been in an empty word.
Compounding the confusion is your check for a backspace '\b' character when you check EOF and other whitespace characters for end of word. It looks more likely that you intended a '\n' but though an off-by-one-key typo you have '\b' instead of '\n'. That is conjecture that you will have to add details to clarify...
A Word-Length Histogram
K&R provides very good exercises and the use of a state-loop is a very good place to start. Rather than multiple-included loops to inch-worm over each word and skip over potentially multiple-included whitespace, you simply keep a state-variable state in your case to track whether you are in a word reading characters, or before the first word, between words or after the last word reading whitespace. While you can simply the check for whitespace by including ctype.h and using the isspace() macro, a manual check of multiple whitespace characters is fine.
While defining in and out macros of 1/0 is fine, simply using a variable and assigning 0 for out or non-zero for in works as well. Since you are keeping a character-count to output a length number of 'X' characters, you can just use your character count variable as your state-variable. It will be zero until you read the first character in a word, and then you would reset it to zero after outputting your length number of 'X's to prepare for the next word.
Initializing all variables, and reading either from the filename given as the first argument to the program, or from stdin by default if no argument is given, you can do something similar to:
#include <stdio.h>
int main (int argc, char **argv) {
int cc = 0, /* character count (length) */
wc = 0; /* word count */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
for (;;) { /* loop continually */
int c = fgetc(fp); /* read character from input stream */
if (c == EOF || c == ' ' || c == '\t' || c == '\n') { /* check EOF or ws */
if (cc) { /* if characters counted */
printf ("%3d : ", wc++); /* output word count */
while (cc--) /* loop char count times */
putchar ('X'); /* output X */
putchar ('\n'); /* output newline */
cc = 0; /* reset char count */
}
if (c == EOF) /* if EOF -- bail */
break;
}
else /* otherwise, normal character */
cc++; /* add to character count */
}
if (fp != stdin) /* close file if not stdin */
fclose (fp);
}
(note: the character-count cc variable is used as the state-variable above. You can use an additional variable like state if that is more clear to you, but think through way using cc above accomplishes the same thing. Also note the change and use of '\n' instead of '\b' as the literal backspace character is rarely encountered in normal input, though it can be generated -- while a '\n' is encountered every time the Enter key is pressed. If you actually want to check for teh backspace character, you can add it to the conditional)
Example Input File
$ cat dat/histfile.txt
my dog has fleas
my alligator has none
Example Use/Output
Using a heredoc for input:
$ cat << eof | ./bin/wordlenhist
> my dog has fleas
> my alligator has none
> eof
0 : XX
1 : XXX
2 : XXX
3 : XXXXX
4 : XX
5 : XXXXXXXXX
6 : XXX
7 : XXXX
Redirecting from a file for input:
$ ./bin/wordlenhist < dat/histfile.txt
0 : XX
1 : XXX
2 : XXX
3 : XXXXX
4 : XX
5 : XXXXXXXXX
6 : XXX
7 : XXXX
Or passing the filename as a argument and opening and reading from the file within your program are all options:
$ ./bin/wordlenhist dat/histfile.txt
0 : XX
1 : XXX
2 : XXX
3 : XXXXX
4 : XX
5 : XXXXXXXXX
6 : XXX
7 : XXXX
Lastly, you can input directly on stdin and generate a manual EOF by pressing Ctrl+d on Linux or Ctrl+z on windows. (note: you will have to press the key combination twice -- can you figure out why?) E.g.
$ ./bin/wordlenhist
my dog has fleas my alligator has none 0 : XX
1 : XXX
2 : XXX
3 : XXXXX
4 : XX
5 : XXXXXXXXX
6 : XXX
7 : XXXX
(also note where the first line of output is placed -- this will help you answer the last question)
If you would like to add a comment below and clarify your intent for int X; and x_count[i] = X; and the use of '\b' I'm happy to help further. Look things over and let me know if you have any questions.

How can fscanf(), in C, be used to read a .gro file?

I am trying to read the following gro file via a C code.
FJP in Pol Water in water t= 0.00000 step= 0
16
1FJP P 1 5.346 7.418 0.319
2FJP P 2 5.151 7.405 0.499
3FJP P 3 5.260 7.178 0.428
4FJP P 4 5.159 6.961 0.342
5FJP P 5 5.355 6.909 0.220
6FJP P 6 5.169 6.824 0.043
7FJP P 7 5.068 6.669 11.454
8FJP P 8 4.919 6.861 11.482
9FJP P 9 4.835 7.075 11.364
10FJP P 10 4.738 6.987 11.197
11FJP P 11 4.847 7.115 10.993
12FJP P 12 4.642 7.126 10.870
13FJP P 13 4.680 6.940 10.674
14FJP P 14 4.521 7.052 10.545
15FJP P 15 4.321 6.973 10.513
16FJP P 16 4.315 6.728 10.516
11.56681 11.56681 11.56681
My code is:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[])
{
char input_file[]="file.gro";
FILE *input;
char *myfile=malloc(sizeof(char)*80);
sprintf(myfile,"%s",input_file); //the .gro file being read in
input=fopen(myfile,"r");
double dummy1,dummy6,dummy7,dummy8,dummy9,dummy10,dummy11;
int dummy2,dummy3,dummy4,dummy5;
int lines=0;
while (fscanf(input,"FJP in Pol Water in water t= %lf step= %d",&dummy1,&dummy2)==2
||fscanf(input," %d\n",&dummy3)==1
||fscanf(input," %dFJP P %d %lf %lf %lf\n",
&dummy4,&dummy5,&dummy6,&dummy7,&dummy8)==5
||fscanf(input," %lf %lf %lf\n",&dummy9,&dummy10,&dummy11)==3)
{
printf("%lf %d\n",dummy1,dummy2);
printf("%d\n",dummy3);
printf("%d %d\n",dummy4,dummy5);
printf("%lf %lf %lf\n",dummy6,dummy7,dummy8);
printf("%lf %lf %lf\n",dummy9,dummy10,dummy11);
lines=lines+1;
}
printf("lines=%d\n",lines);
fclose(input);
}
The problem is the values printed by the various dummy variables do not match what is in the file. Also, the number of lines being read is 3 as opposed to 19, which matches the file. I am not certain what is incorrect about my fscanf() statements to read this file. Any help for this problem would be much appreciated.
Your main problem is that you are assuming scanf is better than it is.
Scanf will read and parse as many arguments as it can, and then give up. It does not rewind to the start of the scanf. Also it treats spaces and newlines (and tabs) as simply "skip all whitespace"
So the line printf("%d\n",dummy3) will try to parse the main lines, eg 1FJP
It will read the digit 1 OK into dummy3, but then get stuck because P != a whitespace.
All the other rules will then get stuck, because none of them expect a P or any string first.
If you want to do it this way, you will just have to apply the scanf statements more intelligently as and when they are expected.
The problem is that you try to read and match the header repeatedly, before each line read (in the while loop.) you should read the head once, then read the lines. You also only need to skip any given piece of whitespace once. So you end up with code like:
if (fscanf(input,"FJP in Pol Water in water t=%lf step=%d%d", &dummy1, &dummy2, &dummy3) != 3) {
fprintf(stderr, "Invalid header\n");
exit(1); }
while (fscanf(input,"%dFJP P%d%lf%lf%lf", &dummy4, &dummy5, &dummy6, &dummy7, &dummy8) == 5) {
... read a line of the table

Leading Zeroes not showing up in c [duplicate]

This question already has answers here:
Extra leading zeros when printing float using printf?
(2 answers)
Closed 5 years ago.
I am trying recreate a sample LC-3 simulator as an assignment, and part of that is to have a 4 digit integer. My code is as follows:
while (read_success != NULL && !done) {
// If the line of input begins with an integer, treat
// it as the memory value to read in. Ignore junk
// after the number and ignore blank lines and lines
// that don't begin with a number.
//
words_read = sscanf(buffer, "%04d", &value_read);
// if an integer was actually read in, then
// set memory value at current location to
// value_read and increment location. Exceptions: If
// loc is out of range, complain and quit the loop. If
// value_read is outside -9999...9999, then it's a
// sentinel -- we should say so and quit the loop.
if (value_read < -9999 || value_read > 9999)
{
printf("Sentinel read in place of Memory location %d: quitting loop\n", loc);
break;
}
else if (value_read >= -9999 && value_read <= 9999)
{
cpu -> mem[loc] = value_read;
printf("Memory location: %02d set to %04d \n", loc, value_read);
cpu -> count++;
loc++;
value_read = NULL;
}
if (loc > 99)
{
printf("Reached Memory limit, quitting loop.\n", loc);
break;
}
read_success = fgets(buffer, DATA_BUFFER_LEN, datafile);
// Gets next line and continues the loop
}
fclose(datafile);
I am reading values from an sdc file with the following values:
1234
3456
-4567;
2353
3434
654
0345
7655
555
9999
10000
The problem is that 0345 shows up as 345, i want 645 to be 0645, and so on.
I tried formatting %d based on a post I saw related to this, but it is not working. Any professional insight?
Edit: I did use %04d to start, but that did not work.
If you want leading zeros to be displayed, use %04d in your printf format.
The 0 is a flag used with d (among others) that says to pad on the left with zeros.

Reading instructions from a text file

I need help with reading instructions from a text file. So for example:
Let's say this is my text file:
a 38
s 20
a 10
s 10
'a' stands for add, 's' stands for subtract, and the number separated by a tab is the number I want to either add or subtract from a total. So I want my program to read this line by line and perform the operation specified.
Example: If my total starts at 0, I want the program to read "a tab 38" on the first line and add 38 to the total, and then move on to the next line and read "s tab 20" on the second line and subtract 20 from the total. So on and so forth.
I know how to get the program to read the file, but I'm not sure how to get it to recognize the a/s, the tab, and the number, and then keep doing it for each line.
Any help would be greatly appreciated because I'm really stuck.
use fscanf(yourfileptr, "%c\t%d", &instruction, &operand) to get the instruction and the operand. then you can simply add or subtract the operand according to the instruction character.
Maybe you can try this . Code I haven't checked properly but that should be the line of coding. This is inside main function code.
FILE *fp;
char buff[255];
char numBuff[10];
int a;
int val = 0;
char op;
int len;
fp = fopen("/tmp/test.txt", "r");
while(fgets(buff, 255, file) != NULL){
len = strlen(buff);
strncpy (numBuff, buff+2, len-2);
numBuff[len-2] = '\0';
a = atoi(numBuff);
if(buff[0] == 's'){
val -= a;
}else if(buff[0]=='a'){
val += a;
}
}
printf("%d",val);

strtok() appends some character to my string

I'm using strtok() to parse a string I get from fgets() that is separated by the ~ character
e.g. data_1~data_2
Here's a sample of my code:
fgets(buff, LINELEN, stdin);
pch = strtok(buff, " ~\n");
//do stuff
pch = strtok(NULL, " ~\n");
//do stuff
The first instance of strtok breaks it apart fine, I get data_1 as is, and strlen(data_1) provides the correct length of it. However, the second instance of strtok returns the string, with something appended to it.
With an input of andrewjohn ~ jamessmith, I printed out each character and the index, and I get this output:
a0
n1
d2
r3
e4
w5
j6
o7
h8
n9
j0
a1
m2
e3
s4
s5
m6
i7
t8
h9
10
What is that "11th" value corresponding to?
EDIT:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char buff[100];
char * pch;
fgets(buff, 100, stdin);
pch = strtok(buff, " ~\n");
printf("FIRST NAME\n");
for(i = 0; i < strlen(pch); i++)
{
printf("%c %d %d\n", *(pch+i), *(pch+i), i);
}
printf("SECOND NAME\n");
pch = strtok(NULL, " ~\n");
for(i = 0; i < strlen(pch); i++)
{
printf("%c %d %d\n", *(pch+i), *(pch+i), i);
}
}
I ran it by:
cat sample.in | ./myfile
Where sample.in had
andrewjohn ~ johnsmith
Output was:
FIRST NAME
a 97 0
n 110 1
d 100 2
r 114 3
e 101 4
w 119 5
j 106 6
o 111 7
h 104 8
n 110 9
SECOND NAME
j 106 0
o 111 1
h 104 2
n 110 3
s 115 4
m 109 5
i 105 6
t 116 7
h 104 8
13 9
So the last character is ASCII value 13, which says it's a carriage return ('\r'). Why is this coming up?
Based on your edit, the input line ends in \r\n. As a workaround you could just add \r to your list of tokens in strtok.
However, this should be investigated further. \r\n is the line ending in a Windows file, but stdin is a text stream, so \r\n in a file would be converted to just \n in the fgets result.
Are you perhaps piping in a file that contains something weird like \r\r\n ? Try hex-dumping the file you're piping in to check this.
Another possible explanation might be that your Cygwin (or whatever) environment has somehow been configured not to translate line endings in a file piped in.
edit: Joachim's suggestion is much more likely - using a \r\n file on a non-Windows system. If this is the case , you can fix it by running dos2unix on the file. But in accordance with the principle "accept everything, generate correctly" it would be useful for your program to handle this file.

Resources