C sscanf (fscanf) behaving differently row from row - c

I've this snippet of code which should read text from input file and put it in a struct.
void load(FILE *fin, struct camion payload[]){
int i=0;
char except;
char buf[1000];
while (fgets(buf,sizeof(buf),fin)){
except='A';
sscanf(buf,"%i-%i-%i %i %s %c",&payload[i].day,&payload[i]. month,&payload[i].year,&payload[i].nparcels,payload[i].origin,&except);
if (except=='E')
payload[i].except=1;
i++;
}
}
The fgets works as it should (tested it), but the fscanf starting with this file:
01-01-2013 354 hub_J
01-01-2013 109 hub_L
03-01-2013 129 hub_J
04-01-2013 265 hub_J
08-01-2013 488 hub_B
09-01-2013 127 hub_J
09-01-2013 136 hub_K
09-01-2013 97 hub_D
10-01-2013 369 hub_O
11-01-2013 455 hub_G
12-01-2013 125 hub_I E
13-01-2013 105 hub_O
13-01-2013 468 hub_C
13-01-2013 360 hub_H E
returns (the printing function is not the problem, the problem happens right when the sscanf is executed) this:
1- 1-2013 354 hub_J
1- 1-2013 109 hub_L
3- 1-2013 129 hub_J
4- 1-2013 265 hub_J
0- 0- 0 0
0- 0- 0 0
0- 0- 0 0
0- 0- 0 0
10- 1-2013 369 hub_O
11- 1-2013 455 hub_G
12- 1-2013 125 hub_I E
13- 1-2013 105 hub_O
13- 1-2013 468 hub_C
13- 1-2013 360 hub_H E
The rows with E mean oversize payload, thus E is not always present, but this shouldn't be the error.
I'm banging my head against the wall.
thanks in advance

Scanning with %i and values with a leading zero are assumed to be octal. 08 and 09 are not octal values. Use %d instead as leading zero's are ignored and values are in base 10.
For the sscanf you might try this. It will scan the five items present in all the lines. The %n specifier will give you the characters processed by the scan. You can then test buf[offset]. If a newline is there, then the entire string was processed. Otherwise there is more to the string and a second sscanf can capture the remaining character.
Disclaimer: I have not compiled and tested this code.
void load(FILE *fin, struct camion payload[]){
int i=0;
int offset=0;
char except;
char buf[1000];
while (fgets(buf,sizeof(buf),fin)){
except='A';
if ( ( sscanf(buf,"%d-%d-%d %d %s%n"
,&payload[i].day
,&payload[i].month
,&payload[i].year
,&payload[i].nparcels
,payload[i].origin
,&offset)) == 5) {
if ( buf[offset] != '\n') {
sscanf(buf+offset, " %c", &except);
}
}
if (except=='E') {
payload[i].except=1;
}
i++;
}
}

Related

Reading data from a text file line by line into arrays using strtok in C

Currently trying to read data from a text file line by line using strtok and a space as a delimiter and save the info into different arrays. Im using the FatFs library to read the file from an sd card. Atm im only trying to read the first 2 elements from the line.
My text file looks like this:
223 895 200 200 87 700 700 700
222 895 200 200 87 700 700 700
221 895 200 200 87 700 700 700
222 895 200 200 87 700 700 700
My current code is something like this:
void sd_card_read()
{
char buffer[30];
char buffer2[10];
char buffer3[10];
int i=0;
int k=0;
int l=0;
int16 temp_array[500];
int16 hum_array[500];
char *p;
FIL fileO;
uint8 resultF;
resultF = f_open(&fileO, "dados.txt", FA_READ);
if(resultF == FR_OK)
{
UART_UartPutString("Reading...");
UART_UartPutString("\n\r");
while(f_gets(buffer, sizeof(buffer), &fileO))
{
p = strtok(buffer, " ");
temp_array[i] = atoi(p);
UART_UartPutString(p);
UART_UartPutString("\r\n");
p = strtok(NULL, " ");
hum_array[i] = atoi(p);
UART_UartPutString(p);
UART_UartPutString("\r\n");
i++;
}
UART_UartPutString("Done reading");
resultF = f_close(&fileO);
}
UART_UartPutString("Printing");
UART_UartPutString("\r\n");
for (k = 0; k < 10; k++)
{
itoa(temp_array[k], buffer2, 10);
UART_UartPutString(buffer2);
UART_UartPutString("\r\n");
}
for (l = 0; l < 10; l++)
{
itoa(hum_array[l], buffer3, 10);
UART_UartPutString(buffer3);
UART_UartPutString("\r\n");
}
}
The output atm is this:
223
0
222
0
etc..
895
0
895
0
etc..
After reading one time it puts the next position the value of 0 in both arrays, which is not what is wanted. Its probably something basic but cant see what is wrong.
Any help is valuable!
If we take the first line of the file
223 895 200 200 87 700 700 700
That lines is, including space and newline (assuming single '\n') 31 characters long. And since strings in C needs to be terminated by '\0' the line requires at least 32 characters (if f_gets works similar to the standard fgets function, and adds the newline).
Your buffer you read into only fits 30 characters, which means only 29 characters of your line would be read and then the terminator added. So that means you only read
223 895 200 200 87 700 700 70
The next time you call f_gets the function will read the remaining
0
You need to increase the size of the buffer to be able to fit all of the line. With the current data it needs to be at least 32 characters. But be careful since an extra character in one of the lines will give you the same problem again.

Reading a File in C isn't working?

so I tried looking around and I couldn't find an answer. I'm trying to read from a file I write in a different program. Writing it works fine, but when I try and read it, there is no output at all. Here's the code.
struct data{
int tp, gpm, deg;
};
int main()
{
struct data list[21];
int p[21];
list[0].tp = 10;
FILE * fout;
fopen("data_list", "r");
for(int i = 0; i < 21; i++){
fscanf(fopen, "%d:\t%d\t%d\t%d\n", &p[i], &list[i].tp, &list[i].gpm, &list[i].deg);
}
for(int i = 0; i < 21; i++){
printf("%d:\t%d\t%d\t%d\n", p[i], list[i].tp, list[i].gpm, list[i].deg);
}
fclose(fout);
return 0;
}
Here's the file I'm trying to read
-10:651 17 108
-9: 514 16 142
-8: 588 16 169
-7: 542 10 160
-6: 531 17 127
-5: 688 15 158
-4: 619 18 122
-3: 658 14 170
-2: 588 11 182
-1: 541 12 139
+0: 641 19 114
+1: 668 17 200
+2: 517 19 157
+3: 589 13 121
+4: 696 13 140
+5: 526 12 157
+6: 630 12 137
+7: 685 11 105
+8: 556 11 120
+9: 645 15 188
+10:624 19 185
Can anyone help me out? I've only been learning C for a couple months, most of it selftaught
fscanf(fopen, "%d:\t%d\t%d\t%d\n"
I have no idea how that possibly even compiled, but you are passing a function pointer where a FILE* is required. That definitely will not work correctly.
The correct thing to pass there is the return value from your fopen() call (which at the moment you've been discarding).

Write a C program that reads in the integers from the accompanying data file and use insertion sort to store the sorted data into an array

Write a C program that implements a simple array-based insertion sort.
Your program must read in the integers from the accompanying data file
and use insertion sort to store the sorted data into an array. If you
must insert an element between two existing values, then you must also
move (or shift) the elements all elements with an index >= the index
where you wish to insert the new element. Note that you can find the
insertion sort algorithm in the textbook and the slides.
This is the ints from the text file. The ints are under each other and not the way they are shown here:
879
646
80
385
741
57
370
240
111
400
262
678
951
506
720
508
792
863
677
864
70
5
591
440
989
478
867
636
278
827
692
243
806
676
158
550
425
226
783
129
876
714
125
721
164
555
730
146
596
947
174
837
48
589
808
868
694
677
379
62
580
165
956
139
215
14
45
552
98
154
702
661
997
825
363
782
229
915
281
397
295
219
231
476
253
22
873
504
653
698
772
184
453
508
977
863
624
947
104
926
This the code I have for now. I am getting the addresses in order but now the integers from the file. When i comment out the insertionSort function, the numbers print fine but obviously not in order. What am i doing wrong?
#include <stdio.h>
#include<stdio.h>
void insertionSort(int *, int);
int main()
{
int i,num,array[1000];
FILE *fp = fopen("data_a5.txt","r");
fscanf(fp,"%d",&num);
if(fp== NULL)
{
printf("Error reading File!\n");
return;
}
while(!feof(fp))
{
fscanf(fp,"%d", &array[num]);
//printf("%d\n", array[num]);
}
insertionSort(array,num);
for(i=0;i<num;i++)
printf("%d\n",&array[i]);
fclose(fp);
return 0;
}
void insertionSort(int *value, int size)
{
int i,j,temp;
for(i = 0; i <= size; i++)
{
for(j = i; j >= 0; j--)
{
if(value[j+1]<value[j])
{
temp=value[j+1];
value[j+1]=value[j];
value[j]=temp;
}
else
break;
}
}
}
If your task is to have your array sorted as items are inserted (ie. "live") you best bet is to use linked structures.
For example:
struct myinst
{
int mynum;
struct myinst *prev;
struct myinst *next;
};
There a lot of examples, here is one: http://www.tutorialspoint.com/data_structures_algorithms/linked_list_program_in_c.htm
When you insert a new item to have your array/linked list sorted you go through your linked list and find the item that is nearest to the new one and then perform an insert by creating new memory an change prev/next addresses in existing items so that they point to the new item.

Reading an indefinite number of integers from a file

I am in the early stages of coding a homework assignment. The larger goal is a little bit bigger and beyond the scope of this question. The immediate goal is to take one or more two digit numbers from the command line which correspond to years (e.g. 52). Then open the file that goes with that year. The files are formatted thusly:
1952 Topps baseball
-------------------
8 10 15 17 20 47 48 49 59 71 136
153 155 159 162 168 170 175 176 186 188 202
215 233 248 252 253 254 257 259 264 270 271 272 274
282 283 284 285 287 293 294 295 297 299 300 308 310 311
312
Each file has a random (between 1-50) number of 1-3 digit integers. I store the year in an int. Then I store each of the later digits into an array. Then I will use that array to do other cool stuff. My problem is, how to I scan for a random number of integer inputs from the file. THis is what I have done so far:
#include <stdio.h>
#include <string.h>
main(int argc, char** argv) {
char filename[30];
int cards[100];
FILE *fp;
int year,n,i;
for (i=1; i<argc; i++) {
n=atoi(argv[i]);
sprintf (filename,"topps.%d",n);
if (!(fp=fopen(filename,"r"))){
printf("cannot open %s for reading\n",filename);
exit(3);
}
fscanf (fp, "%d%*s%*s%*s%d%d%d%d%d%d%d%d%d%d%d%d",
&year,
&cards[i],
&cards[i+1],
&cards[i+2], //this is what needs to be improved upon
&cards[i+3],
&cards[i+4],
&cards[i+5],
&cards[i+6],
&cards[i+7],
&cards[i+8],
&cards[i+9],
&cards[i+10],
&cards[i+11],
&cards[i+12]);
printf ("%d\n",year);
printf ("%d\n",cards[i+11]);
}
}
The current fscanf is just a sort of stopgap to make sure I can read and print the info. It stores up to the 12th integer and prints it. For obvious reasons I didn't want to go to the 50th, because it's pointless. Some files only have 2 or 3 numbers in them. Can anyone help guide me to a more ideal solution for reading files like this? Thanks for having a look.
Something like this does the trick:
Declare 3 new variables at the top:
char sData[10000];
char * pch;
int j = 0;
Then replace your number reading code with the snippet below:
fscanf (fp, "%d%*s%*s%*s", &year);
/* ignore the line with all the dashes (crude, but works)*/
fgets(sData, 10000, fp);
/* read all the number data in */
fgets(sData, 10000, fp);
pch = strtok (sData," ");
j = 0;
while (pch != NULL)
{
cards[j++] = atoi(pch);
pch = strtok (NULL, " ");
}
At the end of this code, cards[] should have all your numbers, and j should contain the count.
I greatly appreciate the help I got from everyone. It definitely led me down the right path. However, this is the answer to the problem that eventually worked for me:
fscanf(fp,"%*[^\n]%*c"); //Skip first two
fscanf(fp,"%*[^\n]%*c"); //lines of file
while (!feof(fp)) { //Read ints into array
fscanf(fp,"%d ",&cards[i++]);
}

sscanf not detecting the right numbers

I'm having a hard time using sscanf to scan hour and minutes from a list. Below is a small snip of the list.
1704 86 2:30p 5:50p Daily
1711 17 10:40a 2:15p 5
1712 86 3:10p 6:30p 1
1731 48 6:25a 9:30a 156
1732 100 10:15a 1:30p Daily
1733 6 2:15p 3:39p Daily
I've tried this, but it keeps getting me segmentation Fault.(I'm putting this information into structures).
for(i=0;i<check_enter;i++){
sscanf(all_flights[i],
"%d %d %d:%d%c %d:%d%c %s",
&all_flights_divid[i].flight_number,
&all_flights_divid[i].route_id,
&all_flights_divid[i].departure_time_hour,
&all_flights_divid[i].departure_time_minute,
&all_flights_divid[i].departure_time_format,
&all_flights_divid[i].arrival_time_minute,
&all_flights_divid[i].arrival_time_minute,
&all_flights_divid[i].arrival_time_format,
&all_flights_divid[i].frequency);
printf("%d ",all_flights_divid[i].flight_number);
printf("%d ",all_flights_divid[i].route_id);
printf("%d ",all_flights_divid[i].departure_time_hour);
printf("%d ",all_flights_divid[i].departure_time_minute);
printf("%c ",all_flights_divid[i].departure_time_format);
printf("%d ",all_flights_divid[i].arrival_time_hour);
printf("%d ",all_flights_divid[i].arrival_time_minute);
printf("%c ",all_flights_divid[i].arrival_time_format);
printf("%s\n",all_flights_divid[i].frequency);
}
This is how I declared it.
struct all_flights{
int flight_number;
int route_id;
int departure_time_hour;
int departure_time_minute;
char departure_time_format;
int arrival_time_hour;
int arrival_time_minute;
char arrival_time_format;
char frequency[10];
};
struct all_flights all_flights_divid[3000];
These are the results I get
1704 86 2 30 p 0 50 p Daily
1711 17 10 40 a 0 15 p 5
1712 86 3 10 p 0 30 p 1
1731 48 6 25 a 0 30 a 156
1732 100 10 15 a 0 30 p Daily
1733 6 2 15 p 0 39 p Daily
Small mistake, that might be the problem:
this:
&all_flights_divid[1].flight_number,
should be:
&all_flights_divid[i].flight_number,
// ^
Edit:
Also, you read arrival_time_minute twice, and not reading arrival_time_hour at all. Fix it and it should be OK.
Most of the results seem to be fine, except the first field.
Now if you check your code..
&all_flights_divid[1]
fix it with
&all_flights_divid[i]

Resources