Variable does not increment in loop that reads file - c

My code reads input in the following format:
The first line has just a number
The other lines have a number and 4 strings
The first line tells the number of following lines.
After reading the file, I want to verify if the number of lines read is the same as specified in the first line. In order to achieve it, I am trying to use a variable count_lines, incrementing it at each iteration of the while loop.
FILE *fp;
char line[MAXLINELEN];
int count_lines = 0;
char city[50], continent[13], cultural[1], outdoors[1];
int total_lines, id;
...
while(fgets(line, sizeof(line), fp))
{
if (count_lines == 0)
{
sscanf(line, "%d", &total_lines);
nodes2 = calloc(sizeof(node), total_lines);
}
else if (sscanf(line, "%d %s %s %s %s", ...)
{
/* code (previously some malloc and strcopy stuff, but the error occurs even without this part of the code) */
}
else
{
/* code */
}
count_lines++;
printf("point \n");
printf("%d\n", count_lines);
}
Data example:
-bash-4.1$ cat places
3
1 City1 Continent1 Y Y
2 City2 Continent1 Y Y
3 City3 Continent1 Y N
However, this is the output of running the code:
point
1
point
1
point
1
point
1
point
1
point
1
point
1
point
1
point
1
point
1
point
1
point
1
I verified that the problem has to do with the else if part. If I comment this part, the counting works correctly. However, I could not figure out why this is happening.
What's wrong with the code?
Note: As this is part of an assignment, I cannot post the whole code.
I omitted irrelevant parts with a /* code */ comment.

strcpy copies second argumet to first argument. In your code you seem to assume the reverse
char *cont_temp = malloc(strlen(continent) + 1);
strcpy(city, cont_temp);
In this case you are copying from cont_temp to city. But cont_temp at this point contains garbage, while city contains the data you just read from file. That's one of the problems. Apparently it should be
strcpy(cont_temp, city);
shouldn't it?
However, I don't understand why you use strlen(continent) to determine the memory size, but then suddenly switch to working with city. That's another problem.

The problem is that cultural and outdoors have size 1, so there's no enough space for the new line character. Defining them with size 2 solves the problem.

Related

Dynamically storing array values in C

What I am doing -
I am trying to read a file that contains information about processes and create 3 different arrays. One for array name, second for arrival time and third for process time and compute it afterwards. The number of processes are not fixed but for testing purposes I am keeping it to 4 processes.
The first printf line outputs what I desire. The file contents in the form of array.
void readFile() {
int i = 0;
char printLine[10];
char *processName[4];
char *arrivalTime[4];
char *processTime[4];
FILE *processFile = fopen("processes.txt", "r");
while(!feof(processFile)){
fgets(printLine, 10, processFile); // get the line
processName[i] = strtok(printLine, " ");
arrivalTime[i] = strtok(NULL, " ");
processTime[i] = strtok(NULL, "");
printf("%s %s %s\n", processName[i], arrivalTime[i], processTime[i]);
i++;
}
printf("----\n%s %s %s\n", processName[0], arrivalTime[0], processTime[0]);
}
Error -
The error(sort of) is that the output of 2nd print line gives me the last process information even though I am printing the 1st element(1st process) information. So, instead of printing 1st element it is printing the last.
processes.txt file looks like this
P1 0 3
P2 1 6
P3 4 4
P4 6 2
P.S.
The format of this file will be fixed so no issue there.
I am a real real novice in this. Please excuse my silliness.
EDIT - my output
This is because of the way strtok works, it doesn't return a pointer to a copy of the token, it returns a pointer to the first character of the token in the ORIGINAL location. You need to create a copy yourself.
basically, after the first read you have the following situation:
[ 1^'P','1','\0',2^'0','\0',3^'3','\0']
1: printLine,processName[0]
2: arrivalTime[0]
3: processTime[0]
So printLine and processName[0] are just pointing at the first position -marked by 1^-.
arrivalTime[0] is just pointing at the 4th position -marked by 2^-.
processTime[0] is just pointing at the 6th position -marked by 3^-.
Where basically all you "string"s -which are actually just character pointers- are pointing to different points within the same sequence of characters.
When you read the new string, it overwrite the old data, but the pointers stay where they are.
After your loop is done you have the following situation:
[ 1^'P','4','\0',2^'6','\0',3^'2','\0']
1:printLine,processName[0],processName[1],processName[2],processName[3]
2:arrivalTime[0],arrivalTime[1],arrivalTime[2],arrivalTime[3]
3:processTime[0],processTime[1],processTime[2],processTime[3]
As you can see, everything is just pointing at different places in the same sequence of characters.

Storing String Inside a String?

My problem is when I try to save the string (series[0]) Inside (c[0])
and I display it, it always ignore the last digit.
For Example the value of (series[0]) = "1-620"
So I save this value inside (c[0])
and ask the program to display (c[0]), it displays "1-62" and ignores the last digit which is "0". How can I solve this?
This is my code:
#include <stdio.h>
int main(void)
{
int price[20],i=0,comic,j=0;
char name,id,book[20],els[20],*series[20],*c[20];
FILE *rent= fopen("read.txt","r");
while(!feof(rent))
{
fscanf(rent,"%s%s%s%d",&book[i],&els[i],&series[i],&price[i]);
printf("1.%s %s %s %d",&book[i],&els[i],&series[i],price[i]);
i++;
}
c[0]=series[0];
printf("\n%s",&c[0]);
return 0;
}
The use of fscanf and printf is wrong :
fscanf(rent,"%s%s%s%d",&book[i],&els[i],&series[i],&price[i]);
Should be:
fscanf(rent,"%c%c%s%d",&book[i],&els[i],series[i],&price[i]);
You have used the reference operator on a char pointer when scanf expecting a char pointer, also you read a string to book and else instead of one character.
printf("1.%s %s %s %d",&book[i],&els[i],&series[i],price[i]);
Should be:
printf("1.%c %c %s %d",book[i],els[i],series[i],price[i]);
And:
printf("\n%s",&c[0]);
Should be:
printf("\n%s",c[0]);
c is an array of char * so c[i] can point to a string and that is what you want to send to printf function.
*Keep in mind that you have to allocate (using malloc) a place in memory for all the strings you read before sending them to scanf:
e.g:
c[0] = (char*)malloc(sizeof(char)*lengthOfString+1);
and only after this you can read characters in to it.
or you can use a fixed size double character array:
c[10][20];
Now c is an array of 20 strings that can be up to 9 characters long.
Amongst other problems, at the end you have:
printf("\n%s",&c[0]);
There are multiple problems there. The serious one is that c[0] is a char *, so you're passing the address of a char * — a char ** — to printf() but the %s format expects a char *. The minor problem is that you should terminate lines of output with newline.
In general, you have a mess with your memory allocation. You haven't allocated space for char *series[20] pointers to point at, so you get undefined behaviour when you use it.
You need to make sure you've allocated enough space to store the data, and it is fairly clear that you have not done that. One minor difficulty is working out what the data looks like, but it seems to be a series of lines each with 3 words and 1 number. This code does that job a bit more reliably:
#include <stdio.h>
int main(void)
{
int price[20];
int i;
char book[20][32];
char els[20][32];
char series[20][20];
const char filename[] = "read.txt";
FILE *rent = fopen(filename, "r");
if (rent == 0)
{
fprintf(stderr, "Failed to open file '%s' for reading\n", filename);
return 1;
}
for (i = 0; i < 20; i++)
{
if (fscanf(rent, "%31s%31s%19s%d", book[i], els[i], series[i], &price[i]) != 4)
break;
printf("%d. %s %s %s %d\n", i, book[i], els[i], series[i], price[i]);
}
printf("%d titles read\n", i);
fclose(rent);
return 0;
}
There are endless ways this could be tweaked, but as written, it ensures no overflow of the buffers (by the counting loop and input conversion specifications including the length), detects when there is an I/O problem or EOF, and prints data with newlines at the end of the line. It checks and reports if it fails to open the file (including the name of the file — very important when the name isn't hard-coded and a good idea even when it is), and closes the file before exiting.
Since you didn't provide any data, I created some random data:
Tixrpsywuqpgdyc Yeiasuldknhxkghfpgvl 1-967 8944
Guxmuvtadlggwjvpwqpu Sosnaqwvrbvud 1-595 3536
Supdaltswctxrbaodmerben Oedxjwnwxlcvpwgwfiopmpavseirb 1-220 9698
Hujpaffaocnr Teagmuethvinxxvs 1-917 9742
Daojgyzfjwzvqjrpgp Vigudvipdlbjkqjm 1-424 4206
Sebuhzgsqpyidpquzjxswbccqbruqf Vuhssjvcjjylcevcisdzedkzlp 1-581 3451
Doeraxdmyqcbbzyp Litbetmttcgfldbhqqfdxqi 1-221 2485
Raqqctfdlhrmhtzusntvgbvotpk Iowdcqlwgljwlfvwhfmw 1-367 3505
Kooqkvabwemxoocjfaa Hicgkztiqvqdjjx 1-466 435
Lowywyzzkkrazfyjuggidsqfvzzqb Qiginniroivqymgseushahzlrywe 1-704 5514
The output from the code above on that data is:
0. Tixrpsywuqpgdyc Yeiasuldknhxkghfpgvl 1-967 8944
1. Guxmuvtadlggwjvpwqpu Sosnaqwvrbvud 1-595 3536
2. Supdaltswctxrbaodmerben Oedxjwnwxlcvpwgwfiopmpavseirb 1-220 9698
3. Hujpaffaocnr Teagmuethvinxxvs 1-917 9742
4. Daojgyzfjwzvqjrpgp Vigudvipdlbjkqjm 1-424 4206
5. Sebuhzgsqpyidpquzjxswbccqbruqf Vuhssjvcjjylcevcisdzedkzlp 1-581 3451
6. Doeraxdmyqcbbzyp Litbetmttcgfldbhqqfdxqi 1-221 2485
7. Raqqctfdlhrmhtzusntvgbvotpk Iowdcqlwgljwlfvwhfmw 1-367 3505
8. Kooqkvabwemxoocjfaa Hicgkztiqvqdjjx 1-466 435
9. Lowywyzzkkrazfyjuggidsqfvzzqb Qiginniroivqymgseushahzlrywe 1-704 5514
10 titles read

bug when reading integers from a text file in C

I am a little bit desperate as I wasted my last 4 hours looking for a solution for a simple/stupid thing. I have a project in school in which I must read integers from a text file and then calculate the maximum of them. The thing is that these numbers are not necessarily separated by spaces, but also tabs ( \t ) or newlines (\n). I use the fscanf function to read my integers, but the problem is that after the last number I have a space in my file, so it reads 2 times the last number(I do not know why). Normally one would say "Just delete that space", but my teacher is going to test the program in several manners, and he warned us that the program must be robust (we have to be able to manage the spaces, \t, \n so we can read correctly the numbers, so this is why he left on purpose a space after the last number). Here is my code with the sample text:
FILE* file = NULL;
int *t = NULL, *new_size = NULL;
int temp, count;
file = fopen(argv[1],"r");
do
{
fscanf(file,"%d",&temp);
count++;
new_size = (int*) realloc (t, count * sizeof(int));
if (new_size != NULL)
{
t = new_size;
t[count-1] = temp;
}
else
{
free(t);
puts("Erreur d\'allocation memoire!\n");
exit(1);
}
} while(!feof(file));
fclose(file);
printf ("Numbers read\n:");
for(i = 0; i < count; i++)
{
printf ("%d ", t[i]);
}
And my argument is a file named data.txt which contains: 3 1 7 0 4 9 6 150 and a \n at the end. So basically, my program reads the first 8 integers, and after that, since it is not EndOfFile, it still reads the last one (150) again. So my output is :
Numbers read:
3 1 7 0 4 9 6 150 150
Could anyone tell me what I should do in order to make my program more robust? I need to manage the same type os error if there is a space at the end, or even a tab (\t).
Any help would be appreciated!
Check the return value of fscanf
if (fscanf(file,"%d",&temp) != 1) break;
and break out of the loop if it doesn't find a number anymore. fscanf returns the number of successful conversions, and that should be used for error checking and handling.
Use the result of fscanf(), which returns the number of assignments made, as the terminating condition of the loop. After the loop check that EOF was reached and the loop did not terminate due to some other failure.
If the numbers are separated by a space, then you can read a space with fscanf and then an integer.To make the program robust, always see if fscanf fails.If it fails then stop reading integers, else continue.
bool good=true;
while(good)
{
char separator;
if(fscanf(file,"%c",&separator)==1)
{
if(separator!=' ' && separator!='\t' && separator!='\n')
{
fprintf(stderr,"Illegal character found in file");
// You can choose if break the loop setting good to false, or
// if to continue, this depends on your assignment
}
if(fscanf(file,"%d",&temp)==1)
{
< Push temp to your list/array >
}
else
{
good=false;
}
}
else
{
good=false;
}
}

How do I read a file in C and store the characters in a variable

I am completely new to C and need help with this badly.
Im reading a file with fopen(), then obtaining the contents of it using fgetc(). What I want to know is how I can access the line fgetc() returns so if I can put the 4th - 8th characters into a char array. Below is an example I found online but am having a hard time parsing the data returns, I still don't have a firm understanding of C and don't get how an int can be used to store a line of characters.
FILE *fr;
fr = fopen("elapsed.txt", "r");
int n = fgetc(fr);
while(n!= EOF){
printf("%c", n);
n = fgetc(fr);
} printf("\n");
Here
1 first open the file
2 get size of file
3 allocated size to character pointer
4 and read data from file
FILE *fr;
char *message;
fr = fopen("elapsed.txt", "r");
/*create variable of stat*/
struct stat stp = { 0 };
/*These functions return information about a file. No permissions are required on the file itself*/
stat("elapsed.txt", &stp);
/*determine the size of data which is in file*/
int filesize = stp.st_size;
/*allocates the address to the message pointer and allocates memory*/
message = (char *) malloc(sizeof(char) * filesize);
if (fread(message, 1, filesize - 1, fr) == -1) {
printf("\nerror in reading\n");
/**close the read file*/
fclose(fr);
/*free input string*/
free(message);
}
printf("\n\tEntered Message for Encode is = %s", message);
PS Dont Forget to Add #include <sys/stat.h>.
You're not retrieving a line with fgetc. You are retrieving one character at a time from the file. That sample keeps retrieving characters until the EOF character is encountred (end of file). Look at this description of fgetc.
http://www.cplusplus.com/reference/clibrary/cstdio/fgetc/
On each iteration of the while loop, fgetc will retrieve a single character and place it into the variable "n". Something that can help you with "characters" in C is to just think of it as one byte, instead of an actual character. What you're not understanding here is that an int is 4 bytes and the character is 1 byte, but both can store the same bit pattern for the same ASCII character. The only different is the size of the variable internally.
The sample you have above shows a printf with "%c", which means to take the value in "n" and treat it like an ASCII character.
http://www.cplusplus.com/reference/clibrary/cstdio/printf/
You can use a counter in the while loop to keep track of your position to find the 4th and 8th value from the file. You should also think about what happens if the input file is smaller than your maximum size.
Hope that helps.
Ok look at it as box sizes I could have a 30cm x 30cm box that can hold 1 foam letter that I have. Now the function I am calling a function that 'could' return a 60cm x 60cm letter but it 99% likely to return a 30cm x 30cm letter because I know what its reading - I know if I give it a 60cm x 60cm box the result will always fit without surprises.
But if I am sure that the result will always be a 30cm x 30cm box then I know I can convert the result of a function that returns aa 60cm x 60cm box without losing anything

Read in Numbers from a File in C

I have a file called points.dat which reads something like:
5
2 5
-1 18
0 6
1 -1
10 0
The first number is how many ordered pairs there are. The next 5 lines contain those ordered pairs. What can I do to read in the first number, determine how many points there are (from here I can malloc an array of structs to store the points in).
My problem is that fgetc doesn't really do the job here. What if the first number is two digits? Say the first number is 10. fgetc will only retrieve the '1'. Also, fgets doesn't really work, since you need to supply it the length of the amount of characters you want to read in. The same applies for fscanf.
The real trouble comes in when it's time to retrieve the ordered pairs. I have no idea how to do this either. My only thoughts so far is look at a line: if it sees non-spaces or non-'\n's, it will read in the number as the x coordinate of point 1. Loop. Get y coordinate. Once it hits a '\n', it will now move on to the next line, and begin looking for values to store in the next struct in the array of structs.
(While doing this, I also need to be sure atoi can convert all of these into integers... ).
If anyone has any ideas to help, they are appreciated.
For the first line use int numValuesRead = fscanf(file, "%d", &totnums);
Then, use numValuesRead = fscanf(file, "%d %d", &num1, &num2); to read the other lines.
fscanf returns the number of value read. You should always check it.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int x, y;
} Point;
int main ()
{
int numOf;
Point *myPoints = NULL;
FILE *myfile = fopen ("myfile.txt","r");
if (myfile == NULL)
perror ("Error opening file"); //or return 1;
else
{
fscanf(myfile, "%d", &numOf);
myPoints = (Point *)malloc(sizeof(Point) * numOf);
while ( !feof (myfile) && numOf-- )
{
fscanf(myfile, "%d %d", &(myPoints[numOf].x), &(myPoints[numOf].y));
}
}
fclose(myfile);
//Do stuff with array
free ((void *)myPoints);
getchar();//Press enter to close debugger etc.
return 0;
}
Sorry for the delay.

Resources