Reputation: 65
I have a problem with output of the make[]
array is giving me. So first I tokenize the file called Carss.txt
, only grabbing the third & fifth column, and store the result in make[]
array and year[]
array respectively.
I tested out the make[]
array to see if it would output the results I wanted. It did inside the while(fgets)
loop, but when I tested it on the outside of while(fgets)
, it's repeating.
I don't understand what's the problem. My program and the text file is provided below.
Output of make array inside while(fgets)
loop: (what I wanted)
FORD
FORD
JAYCO
Output of make array outside while(fgets)
loop:(Not what I wanted)
JAYCO
JAYCO
JAYCO
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
FILE * fp;
char * filename = "Carss.txt";
char lines[100000], blank[100000];
char * token, * del = " ";
int i = 0, c, d = 0, j;
char * make[10000];
char * year[10000];
if ((fp = fopen(filename, "r")) == NULL) /* Opens the file */ {
printf("can't open %s\n", filename);
exit(1);
}
c = 0;
while (fgets(lines, sizeof(lines), fp) != NULL) {
token = strtok(lines, "\t");
i = 1;
while (i < 5) {
token = strtok(NULL, "\t");
if (i == 2) {
make[c] = token;
}
if (i == 4) {
year[c] = token;
}
i++;
}
printf("%s\n", make[c]); /* OUTPUT OF THE ARRAY HERE IS WHAT I WANTED */
c++;
}
c = 0;
while (c < 3) {
printf("%d\n", c);
printf("%s\n", make[c]);
c++;
}
}
The Text File I tokenize: Carss.txt
1 02V288000 FORD FOCUS 2001 02S41 ELECTRICAL SYSTEM:BATTERY:CABLES FORD MOTOR COMPANY 19990719 20010531 V 291854 20030210 ODI Ford Motor Company 20021106 20021106 CERTAIN PASSENGER VEHICLES EQUIPPED WITH ZETEC ENGINES, LOOSE OR BROKEN ATTACHMENTS AND MISROUTED BATTERY CABLES COULD LEAD TO CABLE INSULATION DAMAGE. THIS, IN TURN, COULD CAUSE THE BATTERY CABLES TO SHORT RESULTING IN HEAT DAMAGE TO THE CABLES. BESIDES HEAT DAMAGE, THE "CHECK ENGINE" LIGHT MAY ILLUMINATE, THE VEHICLE MAY FAIL TO START, OR SMOKE, MELTING, OR FIRE COULD ALSO OCCUR. DEALERS WILL INSPECT THE BATTERY CABLES FOR THE CONDITION OF THE CABLE INSULATION AND PROPER TIGHTENING OF THE TERMINAL ENDS. AS NECESSARY, CABLES WILL BE REROUTED, RETAINING CLIPS INSTALLED, AND DAMAGED BATTERY CABLES REPLACED. OWNER NOTIFICATION BEGAN FEBRUARY 10, 2003. OWNERS WHO DO NOT RECEIVE THE FREE REMEDY WITHIN A REASONABLE TIME SHOULD CONTACT FORD AT 1-866-436-7332. ALSO CONTACT THE NATIONAL HIGHWAY TRAFFIC SAFETY ADMINISTRATION'S AUTO SAFETY HOTLINE AT 1-888-DASH-2-DOT (1-888-327-4236). 000015339000215022000000202
2 02V288000 FORD FOCUS 2000 02S41 ELECTRICAL SYSTEM:BATTERY:CABLES FORD MOTOR COMPANY 19990719 20010531 V 291854 20030210 ODI Ford Motor Company 20021106 20021106 CERTAIN PASSENGER VEHICLES EQUIPPED WITH ZETEC ENGINES, LOOSE OR BROKEN ATTACHMENTS AND MISROUTED BATTERY CABLES COULD LEAD TO CABLE INSULATION DAMAGE. THIS, IN TURN, COULD CAUSE THE BATTERY CABLES TO SHORT RESULTING IN HEAT DAMAGE TO THE CABLES. BESIDES HEAT DAMAGE, THE "CHECK ENGINE" LIGHT MAY ILLUMINATE, THE VEHICLE MAY FAIL TO START, OR SMOKE, MELTING, OR FIRE COULD ALSO OCCUR. DEALERS WILL INSPECT THE BATTERY CABLES FOR THE CONDITION OF THE CABLE INSULATION AND PROPER TIGHTENING OF THE TERMINAL ENDS. AS NECESSARY, CABLES WILL BE REROUTED, RETAINING CLIPS INSTALLED, AND DAMAGED BATTERY CABLES REPLACED. OWNER NOTIFICATION BEGAN FEBRUARY 10, 2003. OWNERS WHO DO NOT RECEIVE THE FREE REMEDY WITHIN A REASONABLE TIME SHOULD CONTACT FORD AT 1-866-436-7332. ALSO CONTACT THE NATIONAL HIGHWAY TRAFFIC SAFETY ADMINISTRATION'S AUTO SAFETY HOTLINE AT 1-888-DASH-2-DOT (1-888-327-4236). 000015339000215021000000202
3 02V236000 JAYCO FT EAGLE 10 SG 2003 EQUIPMENT:OTHER:LABELS JAYCO, INC. 20020730 20020813 V 86 20020923 MFR Jayco, Inc. 20020904 20020912 ON CERTAIN FOLDING TENT CAMPERS, THE FEDERAL CERTIFICATION (AND RVIA) LABELS HAVE THE INCORRECT GROSS VEHICLE WEIGHT RATING, TIRE SIZE, AND INFLATION PRESSURE LISTED. IF THE TIRES WERE INFLATED TO 80 PSI, THEY COULD BLOW RESULTING IN A POSSIBLE CRASH. OWNERS WILL BE MAILED CORRECT LABELS FOR INSTALLATION ON THEIR VEHICLES. OWNER NOTIFICATION BEGAN SEPTEMBER 23, 2002. OWNERS SHOULD CONTACT JAYCO AT 1-877-825-4782. ALSO, CUSTOMERS CAN CONTACT THE NATIONAL HIGHWAY TRAFFIC SAFETY ADMINISTRATION'S AUTO SAFETY HOTLINE AT 1-888-DASH-2-DOT (1-888-327-4236). 000015210000106403000000349
Upvotes: 3
Views: 158
Reputation: 36082
strtok operates on a static buffer
when you write
strtok(lines, "\t");
the lines
buffer is copied to an internal static buffer - and strtok has only one static buffer - so every time your while loop iterates, new content is placed intothe static buffer invalidating any previous pointers i.e. make[] and year[].
in order to preserve the tokens you need to allocate separate memory for them which is not destroyed at the end of the loop. this can be done in several ways like using strdup on each string like mentioned by other posters although there would be a lot of bookkeeping then freeing the meory. you could also use another data structure, e.g. a linked list to store the values instead of having lots of pointers:
typedef struct record
{
char make[32]; // lets say the max length of make is 32
char year[10];
struct record* next;
} record;
whenever you read a new line from the file create a new record:
record* first = NULL;
record* last = NULL;
while (fgets(lines, sizeof(lines), fp) != NULL)
{
// first create the record
record* newRecord = malloc(sizeof(record));
newRecord->next = NULL;
// parse the line
int column = 0;
for (char* token = strtok(lines,"\t"); token != NULL; token = strtok(NULL, "\t"), ++column)
{
switch(column)
{
case 2:
strncpy(newRecord->make, token, sizeof(newRecord.make));
break;
case 4:
strncpy(newRecord->year, token, sizeof(newRecord.year));
break;
default: // ignore
break;
}
}
// put in the list
if (first == NULL)
{
first = last = newRecord;
}
else
{
last->next = newRecord;
last = newRecord;
}
}
now you have the parts you are interested in a list. you can print out the list with
for (record* rec = first; rec != NULL; rec = rec->next)
{
printf( "%s, %s\n", rec->make, rec->year );
}
// disclaimer, haven't compiled this.
Upvotes: 0
Reputation: 8406
You are using the wrong data structure to store your results.
The make
array is an array of pointers. This means that all you store there is a memory address, in your case, the memory address of the pointer being used during the strtok
operation. This is not what you want, because you don't know what is going to happen with that memory afterwards; in this case, it appears that during each successive call to the function it gets overwritten.
You need to either use a multidimensional array or to use malloc()
or strdup()
to create a copy of the char *
value as returned by strtok()
.
Upvotes: 0
Reputation: 25579
When you do this:
token = strtok(NULL, "\t");
if(i==2)
{
make[c] = token;
}
You do not take a copy of the string, only a pointer reference to it. Then the next time you call fgets
the string is overwritten, and all the references point to the new string. So, when you get to the end of the program all your pointers point to the last thing that was written to that memory.
Try this:
make[c] = strdup(token);
That will allocate new memory, duplicate the string, and return the new pointer. The copy will not get overwritten. strdup
calls malloc
, internally, so you should free
the memory when you are done with it.
Upvotes: 4
Reputation: 67743
Inside the loop, make[c] = token
records an address inside char lines[]
. Since that buffer is overwritten on the next iteration, you need to copy your tokens somewhere else to keep them safe.
Just use make[c] = strdup(token)
(and the same for year) to do this - but remember in any real program, you should now free
all your make and year strings when you're done with them.
Upvotes: 1