Calculating bytes returned from read operation - c

I have a program that reads from STDIO_FILENO. The input source is a txt file which contains 15 integers. After calling read and storing the returned value in n. I inspect it with gdb print n. Gdb tells me that read returned 45 bytes. I was expecting 60 bytes based on (32bit x 15) / 8. Can someone explain to me where I'm making the bad calculation.
#define BUFFSIZE 4096
int main(int argc, char * argv[])
{
int n;
char buf[BUFFSIZE];
while((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)
if(write(STDOUT_FILENO, buf, n) != n)
err_sys("write error");
if(n < 0)
err_sys("read error");
exit(0);
}
Breakpoint 1, main (argc=1, argv=0x7fff5fbffb38) at stdin_stdout.c:10
10 while((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)
(gdb) print n
$1 = 0
(gdb) n
Breakpoint 2, main (argc=1, argv=0x7fff5fbffb38) at stdin_stdout.c:11
11 if(write(STDOUT_FILENO, buf, n) != n)
(gdb) print n
$2 = 45

You are confusing numbers with representations of numbers. Since this is a text file, it contains text, not integers.
You can, for example, convert the text "12 32" into the integer twelve and the integer thirty-two, but you have to do it. You have to use base 10 and you have to agree that a space separates integers. The text will be five bytes if each character is one byte. You can then convert it into 8 bytes (two 32-bit integers) if you want. But that conversion has to actually be done, it doesn't do itself.

Related

How read a variable number of int from a string

I have the following text file
0 0 0 debut
1 120 0 permis exploitation
2 180 1 1 piste 6km
3 3 1 2 installation sondeuses
4 30 1 2 batiments provisoires
5 60 1 2 groudronnage piste
6 90 1 4 adduction eau
7 240 2 3 4 campagne sondage
8 180 3 5 6 7 forage 3 puits
9 240 3 5 6 7 construction bureaux logements
10 30 2 8 9 transport installation matériel
11 360 2 8 9 traçage du fond
12 240 2 8 9 construction laverie
13 0 3 10 11 12 fin des travaux
Each line is the representation of a task and is described as followed: the first number is and ID, the second is the duration, the third is the number of previous tasks that are required, and all the numbers afterward are the IDs of the required tasks. Finaly the string in the end is the title of the string.
I'm trying to fill an array of those struct by reading this file. Here is the struct:
typedef struct{
int id;
int duration;
int nbPrev; /* number of required previous tasks */
int prev[NMAXPREV]; /*array of required previous tasks*/
char title[LGMAX];
}Task ;
Here is my code to read the file
int readTasksFile(char* file_name, Task t[])
{
FILE* f;
char line[256] = {'\0'};
int i = 0;
char c[1] = {0};
if((f = fopen(file_name, "r")) == NULL)
{
perror("The file couldn't be opened");
exit(EXIT_FAILURE);
}
while (fgets(line, 256, f) != EOF)
{
sscanf_s(line, "&d &d &d", &(t[i].id), &(t[i].duration), &(t[i].nbPrev));
i++;
}
fclose(f);
return 0;
}
How can I read all the previous tasks number in a line considering it is variable and still be able to read the title afterward ?
How can I read all the previous tasks number in a line considering it is variable and still be able to read the title afterward ?
The 3rd int should be the number of following ints.
Use "%n" to record scan offset.
After reading the .prev[], copy the rest of the line to .title.
Add error checking. This is very important, especially for complex input.
// Untested code to get OP started
// while (fgets(line, 256, f) != EOF) Comparing against EOF is incorrect
while (fgets(line, sizeof line, f)) {
int offset = 0;
// Use %d, not &d
if (sscanf(line, "%d %d %d %n",
&t[i].id, &t[i].duration, &t[i].nbPrev, &offset) != 3) {
// Handle bad input, for now, exit loop
break;
}
if (t[i].nbPrev < 0 || t[i].nbPrev > NMAXPREV) {
// Handle bad input, for now, exit loop
break;
}
char *p = line + offset;
int prev;
// Populate t[i].prev[]
for (prev = 0; prev < t[i].nbPrev; prev++) {
if (sscanf(p, "%d %n", &t[i].prev[prev], &offset) != 1) {
break;
}
p += offset;
}
if (prev != t[i].nbPrev) {
// Handle bad input, for now, exit loop
break;
}
// remaining text
int len = strlen(p);
if (len > 0 && p[len-1] == '\n') p[--len] = '\0'; // consume potential trailing \n
if (len >= LGMAX) {
// Handle bad input, for now, exit loop
break;
}
strcpy(t[i].title, p);
i++;
}
return i; // Let caller know of successful lines parsed.
Advanced: robust code would use strtol() instead of "%d" and sscanf().
readTasksFile() should also pass in the max number of Task t[] that can be read.
You could also scan by line and assign the two first numbers to id and duration, then do an int analysis and add the rest of the elements to nbPrev until you encounter a letter.
I don't know if this would be the best way to do it, but it's how I would do it.
Why don't you create also a list each time you register in struct nbPrev?
Like, instead of nbPrev being of type int, make it of type list?

What are these numbers that convert to text?

/***
* Author: Omar IRAQI
*/
#include <stdio.h>
#include <stdlib.h>
#define N 11
int main(void) {
int i, *p, encoded_message[] = {1634558290, 544104804, 1701994827, 539782501, 1918985572,
1970565920, 1953391972, 1226845811, 1936289056, 1870209139, 8565};
char *message;
printf("%s\n", (char*)encoded_message);
/**
* Let's say it again!
*/
message = (char*)malloc(N * sizeof(int));
p = (int*)message;
for (i=0; i < N; i++, p++)
*p = encoded_message[i];
printf("%s\n", message);
return 0;
}
this outputs the message twice:
Ramadan Kareem, dear students. I miss you!
I was wondering what these encoded numbers are since they don't match with ASCII code
Each int should be split into 4 bytes to recover the individual ascii codes. You could simply print each int as hex.
You can also calculate:
1634558290 % 256
(1634558290 >> 8) % 256
(1634558290 >> 16) % 256
and so on.
You have 11 x 4 byte integers for a total of 44 bytes. This corresponds closely to the length of the message.
1 634 558 290 = 0x616D6152
52 : R
61 : a
6D : m
61 : a
Lookup little endian vs big endian for why the bytes are inverted.

C Programming Occurrences of an Integers in an Text File

Problem: Write a program that reads all integers that are in the range
of 0 to 100, inclusive from an input file named: a.txt and counts how
many occurrences of each are in the file. After all input has been
processed, display all the values with the number of occurrences that
were in are in the input file.
Note: The program ignores any number less than 0 or greater than 100.
Note: Do not display zero if a number is not in the file. Hints: An
array of size 101 is good enough. A number in the file plays the role
of an index.
For example: Suppose the content of the file: a.txt is as follows:
99 2 99
3
-12 80 12 33
3 99 100 1234 84
The display output is:
2 has occurred: 1 times,
3 has occurred: 2 times,
12 has occurred: 1 times,
33 has occurred: 1 times,
80 has occurred: 1 times,
84 has occurred: 1 times,
99 has occurred: 3 times,
100 has occurred: 1 times
Here is the code that I have right now:
#include <stdio.h>
#include <stdlib.h>
int main(){
FILE *inFile;
int count = 1, num[101];
inFile = fopen("a.txt", "r");
for(int i = 1; i <= 100; i++) {
fscanf(inFile, "%d", &num[i]);
}
for(int i = 1; i <= 100; i++){
if(num[i] == i) {
printf("%i has occurred: %d times\n", i, count);
count++;
}
}
fclose(inFile);
}
Output:
2 has occured: 1 times
Hello, I'm trying to do this assignment for my C Programming class due Sunday at midnight, but I'm having trouble trying to print all of the numbers from the array with their occurrences. In my code, I first declared int count to increase the number of occurrences if the number is found more than once in the text file and created an array size of 101. Then, I used a for loop to read the text file and store all the numbers from 1-100 into the array. The second for loop, followed by an if statement is to compare the numbers from the array. Even though this is a test program, we are supposed to be able to do this with all data values. Hope this is a good enough explanation, thank you.
You are close.
Instead of reading each value into num, You want to use your num array to keep the count of each number seen in the file.
int main() {
FILE* inFile;
int value = 0;
int result = 0;
int num[101] = { 0 }; // zero-init this array
inFile = fopen("a.txt", "r");
if (inFile == NULL) {
printf("unable to open file\n");
return -1;
}
result = fscanf(inFile, "%d", &value);
while (result == 1) {
printf("Just read: %d\n", value);
if ((value >= 0) && (value <= 100)) {
num[value] = num[value] + 1; // num[value]++
}
result = fscanf(inFile, "%d", &value);
}
for (int i = 0; i <= 100; i++) {
if (num[i] > 0) {
printf("%i has occurred: %d times\n", i, num[i]);
}
}
fclose(inFile);
}
In addition to the good answer by #selbie, from my answer to your earlier question How do I get the counter to work..., you can apply the same principals to filling a Frequency Array here. In this case you simply use n as an index instead of a counter.
For example with your index n and your array num declared (and initialized all zero), you would simply read all integers in the file and check if the value n was between 0 <= n <= 100 and if so , update the value at the index n in your num array by one, e.g. num[n]++;. You could do it like:
int n = 0; /* index */
int num[NELEM] = {0}; /* array */
...
while (fscanf(myFile, "%d", &n) == 1) /* read each int */
if (0 <= n && n <= 100) /* if 0 <= n <= 100 */
num[n]++; /* increment value at index */
Then for your output, you just handle your special check on num[0] to determine whether to output that index, and then loop from 1-NELEM outputting the frequency of occurrence of each value, e.g.
if (num[0]) /* check if 0 found, output if so */
printf ("num[%3d] occurred %3d times\n", 0, num[0]);
for (int i = 1; i < NELEM; i++) /* output counts for 1-100 */
printf ("num[%3d] occurred %3d times\n", i, num[i]);
The complete example could be:
#include <stdio.h>
#define NELEM 101 /* if you need a constant, #define one (or more) */
int main(int argc, char **argv) {
int n = 0; /* index */
int num[NELEM] = {0}; /* array */
/* read filename from 1st argument (stdin by default) */
FILE *myFile = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!myFile) { /* validate myfile is open for reading */
perror ("fopen-myfile");
return 1;
}
while (fscanf(myFile, "%d", &n) == 1) /* read each int */
if (0 <= n && n <= 100) /* if 0 <= n <= 100 */
num[n]++; /* increment value at index */
if (myFile != stdin) /* close file if not stdin */
fclose (myFile);
if (num[0]) /* check if 0 found, output if so */
printf ("num[%3d] occurred %3d times\n", 0, num[0]);
for (int i = 1; i < NELEM; i++) /* output counts for 1-100 */
printf ("num[%3d] occurred %3d times\n", i, num[i]);
}
Example Use/Output
With 500 random integers in a file, you would get output similar to:
$ ./bin/fscanffreq dat/500_rand_0-100.txt
num[ 0] occurred 3 times
num[ 1] occurred 8 times
num[ 2] occurred 7 times
num[ 3] occurred 2 times
num[ 4] occurred 1 times
num[ 5] occurred 4 times
num[ 6] occurred 3 times
num[ 7] occurred 5 times
num[ 8] occurred 6 times
num[ 9] occurred 4 times
num[ 10] occurred 6 times
...
num[ 95] occurred 6 times
num[ 96] occurred 4 times
num[ 97] occurred 6 times
num[ 98] occurred 2 times
num[ 99] occurred 5 times
num[100] occurred 6 times
(note: if num[0] was 0, it would not be displayed)
Look things over and let me know if you have further questions.

C - Appending strings at beginning and end of while loop

I'm trying to construct a string - for every 80 chars in the loop, to add 7 tabs to the beginning of the line, and a new line at the end.
It should print out 7 tabs, then 80 chars, then 1 new line and so on.
However, something strange is happening. It's printing a new line straight after the first 2 chars and then everything is skewed from then on.
I'm also not sure why I need % 40 rather than % 80 - is it because there are 2 bytes?
I think generally im getting confused by 2 bytes.
void do_file(FILE *in, FILE *out, OPTIONS *options)
{
char ch;
int loop = 0;
int sz1,sz2,sz3;
int seeker = offsetof(struct myStruct, contents.datas);
//find total length of file
fseek(in, 0L, SEEK_END);
sz1 = ftell(in);
//find length from beggining to struct beginning and minus that from total length
fseek(in, seeker, SEEK_SET);
sz2 = sz1 - ftell(in);
int tabs = (sz2 / 80) * 8;// Total size / size of chunk * 8 - 7 tabs and 1 new line char
sz3 = ((sz2 + 1 + tabs) * 2); //Total size + nuls + tabs * 2 for 2 bytes
char buffer[sz3];
char *p = buffer;
buffer[0] = '\0';
while (loop < sz2)
{
if(loop % 40 == 0){
//Add 7 tabs to the beginning of each new line
p += sprintf(p, "%s", "\t\t\t\t\t\t\t");
}
fread(&ch, 1, 1, in);
//print hex char
p += sprintf(p, "%02X", (ch & 0x00FF));
if(loop % 40 == 0){
//Add a new line every 80 chars
p += sprintf(p, "%s", "\n");
}
strcat(buffer, p);
loop++;
}
printf("%s", buffer);
}
However, something strange is happening. It's printing a new line straight after the first 2 chars and then everything is skewed from then on.
It's because of the initial value of loop, try with int loop = 1;
I'm also not sure why I need % 40 rather than % 80 - is it because there are 2 bytes?
I think generally im getting confused by 2 bytes.
The point is, for each character you read in input file, you write two characters in buffer, because you decided to print characters as two bytes (%02X).
Now what is your need:
insert LF and tabs each 80 characters of the input file? (Is that your expecting?)
insert LF and tabs each 80 characters of the output? (That is what you coded)

reading a number line by line and split it to multiple variable in C

samplegame.txt(actual_file)
6
2 3 3
11 2
18 1
10 3
22 14
30 19
8 16
12 24
20 33
i want to read data .txt file into my C program.for each line separate them and store them in the variable,so i can use in further step.i'm trying to use
FILE* file = fopen (argv[1], "r");
int i = 0;
fscanf (file, "%d", &i);
while (!feof (file))
{
//printf ("%d ", i);
fscanf (file, "%d", &i);
}
fclose (file);
but i got all the number in one line and can't figure out how to separate each group like
int board_size = 6 << 1st line
int minion_box_size = 2; << 2nd line
int trap_size = 3;
int trampoline_size = 3;
int minion_box[minion_box_size] = {11,18}; << 3rd to N line
int minion_walk[minion_box_size] = {2,1};
int trap_position[trap_size] = {10,22,30}; << N+1 to M line
int trap_end[minion_box_size] = {3,14,19};
int trampoline_position[trampoline_size] = {8,12,20}; << M+1 to k line
int trampoline_jump[trampoline_size] = {16,24,33};
Anyone has a suggestion ?
samplegame.txt(explained)
______Board_________
6 // size of game board
_____size of each item_________
2 3 3 // first number in this line is Minion_box,which means there is 2 Minion_box
// Second number is trap_holes,which means there is 3 traps
// third number is trampoline,which means there is 3 trampolines
_____Minion_Box_______
// first number : where the minion_box are
// Second number : how many step that the minion can walk
11 2 // the box is in 11th block , minion has aiblity to walk 2 step
18 1 // the box is in 18th block , minion has ability to walk 1 step
______Traps__________
// first number : where the traps are
// Second number : the block you gonna be,after stepping on the trap.
10 3 // there is a trap hole in the 10th block,step on it and you will fall down 3rd block
22 14 // a trap hole in the 22th block,fall down to 14th block
30 19 // a trap hole in the 30th block,fall down to 19th block
____trampoline_______
// first number : where the trampoline are
// Second number : the block you gonna be,after stepping on the trampoline.
8 16 // there is a trampoline in 8th block,if you step on it you will jump to 16th block
12 24 // trampoline in 12th block,jump to 24th block
20 33 // trampoline in 20th block,jump to 33th block
Sorry for bad english and really long post,since i'm not good in english so i'm trying to show the example as much as possible :(
If you want to read a file line after line, better use fgets() and sscanf().
char buffer[BUFFER_SIZE]; // with a #define BUFFER_SIZE 1024 or whatever sooner in the code
int first_value, second_value;
if (fgets(buffer, BUFFER_SIZE, f) == NULL)
{
if ferror(f)
{
perror("");
}
exit(1);
}
if (sscanf(buffer, "%d %d", &first_value, &second_value) != 2)
{
fprintf(stderr, "missing value\n");
exit(1);
}

Resources