I am fairly new to the C language and allocating memory/using pointers in general. Anyway, I was experimenting with reading a file, putting those values in a struct, etc. I know exactly what I want to do and of course the program runs but the output is incorrect and some kind of jumbled numbers and letters.
There is a text file with new information for each line. Each line represents one object.
This is how a line in the file might look:
meat sirloin 6.55 8 8.50 4
Overall I want to be able to store all of my PRODUCT objects in an array (so I have an array of structs). So I attempted to allocate memory with a pointer, use a line count, and then send the pointer to a function called read. In read I add each struct to the array via a pointer. The program doesn't crash, the output is just not correct and I have no clue why not. It's prob something with pointers. If anyone could help me I would really appreciate it. Any help at all would be great.
//prototype
void read(pointerToArr);
typedef struct
{
char supType[15];
char prodName[15];
double wholePrice;
int quantWhole;
double retPrice;
int retProdQuantity;
}PRODUCT;
FILE *fr;
int lineCount = 0;
int main()
{
PRODUCT *ptr;
int i;
char check[50];
fr = fopen("ttt.txt", "r");
while(fgets(check, sizeof(check), fr)!= NULL)
{
if(check[0] != '\n')
{
lineCount++;
}
}
// allocate memory for array based on line count.
PRODUCT prodContainter[lineCount];
ptr = (PRODUCT*)malloc(sizeof(PRODUCT)*lineCount);
ptr = prodContainter;
read(ptr);
//print after adding to array via pointer from other
//function. this was a test.
for(i = 0; i < lineCount; i++)
{
printf("%s ", prodContainter[i].supType);
printf("%s ", prodContainter[i].prodName);
printf("%f ", prodContainter[i].wholePrice);
printf("%d ", prodContainter[i].quantWhole);
printf("%f ", prodContainter[i].retPrice);
printf("%d\n\n", prodContainter[i].retProdQuantity);
}
return 0;
}
void read(PRODUCT *pointerToArr)
{
// objective in this method is to read in data from the file, create an object for every line and
// then use the pointer array to add those objects to prodConstainer up above.
char supplyName[15];
char productName[15];
double wholeP = 0;
int quantityWhole = 0;
double retailPrice = 0;
int retailProductQuant = 0;
while(fscanf(fr, "%s %s %lf %d %lf %d", supplyName, productName, &wholeP, &quantityWhole, &retailPrice, &retailProductQuant) == 6)
{
PRODUCT record;
int i;
strcpy(record.supType, supplyName);
strcpy(record.prodName, productName);
record.wholePrice = wholeP;
record.quantWhole = quantityWhole;
record.retPrice = retailPrice;
record.retProdQuantity = retailProductQuant;
for(i = 0; i < lineCount; i++)
{
pointerToArr[i] = record;
}
}
fclose(fr);
}
You never rewind the file, so all the reading after you count the number of lines fails.
What you're printing is just what happens to be in memory.
There are many ways to fix this, of course.
Rewind the file, using rewind()
Close the file and let your read() function (whose name collides with a POSIX standard function, btw) re-open the file. This would also involve removing the scary global variable fr.
Re-structure so you never count the number of lines, by just reading and letting the ptr array grow as necessary (see realloc()).
Also, you should really avoid casting the return value of malloc() in C. This:
ptr = (PRODUCT*)malloc(sizeof(PRODUCT)*lineCount);
is better written as:
ptr = malloc(lineCount * sizeof *ptr);
This does away with the cast, and also uses sizeof on a value of the type pointed at to automatically compute the proper number of bytes to allocate.
Related
I'm working on this C project (I'm fairly new to C), where I have to parse data from a file into a 2D array which is an element of a structure defined as follows:
typedef struct {
int x;
int y;
char ** result;
} gameF;
The file contains two integers at the top and these integers dictate the size of the 2D array result, while the data to be entered into this array is in a newline below them. Thus far, I have written the following code, but keep getting a segmentation error. I know that the problem lies somewhere between lines 11 and 16, since I have tried the rest of the code after commenting out these lines and it works fine.
gameF * Parsefile(char * fp){
FILE * ResData;
ResData = fopen(fp, "r");
gameF * MyF = malloc(sizeof(gameF));
char line[52];
while(fgets(line, 52, ResData) !=NULL){
int num = 0;
if(sscanf(line, "%d %d", &(*MyF).x, &(*MyF).y) != 0){
continue;
}
int i; // L11
for(i=0; i<52; i++){
if(line[i]==' '){
break;
}
(*MyF).result = line [i]; // L16
}
num ++;
}
return MyF;
}
Please help!
You are not allocating space (malloc) to (*MyF).result, before the assignment at line 16.
So the pointer is pointing to an invalid location in memory.
Also you are assigning the to member result to a single char (instead of a string) with
(*MyF).result = line [i];
I'm trying to code my own Turing machine. My program takes two files as arguments: my initial tape the machine will have to work with, and a rule file. This rule file consists in one rule per line, and each rule is five integers: current state, symbol found, new symbol, direction for the head to go, and new state. For that, I have a function that reads my file and puts each set of five ints found in a rule structure. An array of these structures is then generated.
What I'm trying to do is to return this array in order to be able to use it later on. Here is what I have :
struct rule {
int cur_state;
int symbol;
int new_symbol;
int direction;
int new_state;
};
typedef struct rule rule;
struct vect {
int nb_elem;
rule *p;
};
vect rule_generator (char * file_rule){
int line_number = 0;
int ligne;
char tmp;
rule rule_list[line_number];
vect output_rules;
FILE * file;
file = fopen(file_rule, "r");
for(tmp = getc(file); tmp != EOF; tmp = getc(file)){
if ( tmp == '\n')
line_number++;
}
output_rules.p = malloc(line_number*sizeof(rule));
assert(output_rules.p);
output_rules.nb_elem = line_number;
for (ligne = 0; ligne < line_number; ligne++ ){
fscanf(file, "%d %d %d %d %d", &rule_list[ligne].cur_state,
&rule_list[ligne].symbol, &rule_list[ligne].new_symbol,
&rule_list[ligne].direction, &rule_list[ligne].new_state);
}
fclose(file);
return output_rules;
}
int main (int argc, char *argv[]){
vect rule_list = rule_generator(argv[2]);
printf("symbole : %ls \n", &rule_list.p[0].symbol);
return 0;
}
As some of you may already have guessed, this doesn't print anything... I've been scratching my head for a while, trying to access my array. I could really use a hand here!
Few problems here.
You are declaring array with size 0.
int line_number = 0;
rule rule_list[line_number];
You don't need rule_list just remove it.
output_rules is no where being initilized other than memory allocating.
Solution:
I would suggest you to use output_rules for fscanf.
for (ligne = 0; ligne < line_number; ligne++ ){
fscanf(file, "%d %d %d %d %d", &output_rules.p[ligne].cur_state,
&output_rules.p[ligne].symbol, &output_rules.p[ligne].new_symbol,
&output_rules.p[ligne].direction, &output_rules.p[ligne].new_state);
}
Also did you mean to print the value of symbol?
As you are using %ls which is used to wchar_t *.
printf("symbole : %ls \n", &rule_list.p[0].symbol);
should be
printf("symbole : %d \n", rule_list.p[0].symbol);
There's lots going on here.
The main problem seems to be that this loop:
for(tmp = getc(file); tmp != EOF; tmp = getc(file)){
if ( tmp == '\n')
line_number++;
}
is going right the way through the file to the end, which means there's nothing left for fscanf() to read. If you want to read the whole file through once to find out the number of lines, and then read it again to read the content, you're going to have to either a) close and reopen it, or b) use the rewind() or fseek() function to go back to the start of the file.
(To be honest, an even better solution would be to design your code so that you don't need to read the file twice over. If you end up trying this and get stuck, ask again with a new question on this site.)
In addition, you should add these lines at the beginning of your code:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
to read in the header files which define the functions you're using, and put this line after your struct vect definition to define the type:
typedef struct vect vect;
Also, please run your compiler with warnings enabled. This would have helped you find some of these problems yourself!
so I'm having a little problem with my struct array not doing what its supposed to. I get no compiler warnings or errors when building the program.
int Array_Size=0;;
int Array_Index=0;
FILE *Writer;
struct WordElement
{
int Count;
char Word[50];
};
struct WordElement *StructPointer; //just a pointer to a structure
int Create_Array(int Size){
StructPointer = (struct WordElement *) malloc(Size * sizeof(StructPointer));
Array_Size = Size;
return 0;
}
int Add_To_Array(char Word[50]){
int Word_Found=0;
for(int i=0; i <= Array_Size && Word_Found!=1; i++)
{
if(strcmp(StructPointer[i].Word, Word)) // This should only run if the word exists in struct array
{
StructPointer[i].Count++;
Word_Found=1;
}
}
if(Word_Found==0) // if the above if statement doesnt evualate, this should run
{
strcpy(StructPointer[Array_Index].Word, Word); //copying the word passed by the main function to the struct array at a specific index
printf("WORD: %s\n", StructPointer[Array_Index].Word); // printing it just to make sure it got copied correctly
Array_Index++;
}
return 0;
}
int Print_All(char File_Name[50])
{
Writer = fopen(File_Name, "w");
printf("Printing starts now: \n");
for(int i=0; i < Array_Size; i++)
{
fprintf(Writer, "%s\t\t%d\n",StructPointer[i].Word, StructPointer[i].Count);
}
free(StructPointer);
return 0;
}
These functions get called from a different file, The Add_To_Array is called when the program reads a new word form the text file. That function is supposed to check if the word already exists in the struct array and if it does, it should just increment the counter. If it doesn't, then it adds it.
The Print_All function is called after all the words have been stored in the struct array. Its supposed to loop through them and print each word and their occurrence. In the text file, there are 2 of every words but my program outputs:
this 13762753
document -1772785369
contains 1129268256
two 6619253
of 5701679
every 5570645
word 3342389
doccontains 5374021
I don't know what to make of this as im really new to C programming... It's probably worth mentioning the if(Word_Foun==0) doesn't execute
StructPointer = malloc(Size * sizeof(*StructPointer));
This will be the correct allocation. Otherwise you will have erroneous behavior in your code. Also check the return value of malloc.
StructPointer = malloc(Size * sizeof(*StructPointer));
if(NULL == StructPointer){
perror("malloc failure");
exit(EXIT_FAILURE);
}
You are allocating for struct WordElement not a for a pointer to it. You already have a pointer to struct WordElement all that you needed was memory for a struct WordElement.
Also in the loop you are accessing array index out of bound
for(int i=0; i <= Array_Size && Word_Found!=1; i++)
^^^
It will be i < Array_Size.
In case match occurs you want to set the variable Word_found to 1.
if(strcmp(StructPointer[i].Word, Word) == 0){
/* it macthed */
}
Also Writer = fopen(File_Name, "w"); you should check the return value of fopen.
if(Writer == NULL){
fprintf(stderr,"Error in file opening");
exit(EXIT_FAILURE);
}
Also when you are increasing the Array_index place a check whether it might access the array index out of bound.
The more global variable you use for achieving a small task would make it more difficult to track down a bug. It is always problematic because the places from which data might change is scattered - making it difficult to manage.
I'm writing a homework program in C. The program should take records from an input file and write those record to an output file. It seems like there is something wrong with the print_to_file function. I keep getting segmentation fault 11. Please help. My code is as below.
#include <stdio.h>
#include <stdlib.h>
typedef struct car { // create a struct type Car
char *license_plate;
int parking_spot;
int num_tickets;
int time_left;
} Car;
#define LICENSEPLATELENGTH 10
Car* import_cars(char *filename, int numCars);
void print_to_file(char* filename, Car* garage, int numCars);
int main(int argc, char * argv[]) {
if(argc != 4)
printf("Incorrect input.\n");
else {
int number = atoi(argv[1]);
Car* parked_car = (Car*)malloc(sizeof(Car) * number);
parked_car = import_cars(argv[2], number);
print_to_file(argv[3], parked_car, number);
free(parked_car);
}
return 0;
}
Car* import_cars(char* filename, int numCars)
{
Car* inCar = (Car*)malloc(sizeof(Car) * numCars);
inCar->license_plate = (char*)malloc(sizeof(char) * 8);
//Question: How do I do if I the plate length is varied. How to malloc space to it?
FILE* inFilePtr;
if((inFilePtr = fopen(filename, "r")) == NULL)
printf("Error! Unable to open file %s. Check again.\n", *filename);
else
{
int i = 0;
fscanf(inFilePtr, "%s", inCar[i].license_plate);
fscanf(inFilePtr, "%d%d%d", inCar[i].parking_spot, inCar[i].num_tickets, inCar[i].time_left);
printf("%s %d %d %d \n", inCar[i].license_plate, inCar[i].parking_spot, inCar[i].num_tickets, inCar[i].time_left);
for(i = 1; i < numCars; i++)
{
fscanf(inFilePtr, "%s", inCar[i].license_plate);
fscanf(inFilePtr, "%d%d%d", inCar[i].parking_spot, inCar[i].num_tickets, inCar[i].time_left);
printf("%s %d %d %d \n", inCar[i].license_plate, inCar[i].parking_spot, inCar[i].num_tickets, inCar[i].time_left);
}
}
fclose(inFilePtr);
return(inCar);
//free(inCar.license_plate); `
//Question: Do I need to free space here would it remove the value
//stored in the variable which passed to main?
}
void print_to_file(char* filename, Car* garage, int numCars) {
FILE* outFilePtr;
if((outFilePtr = fopen(filename, "w+")) == NULL){
printf("Error! Cannot Open File %s!", *filename);
printf("here\n");
} else {
int i = 0;
for(i = 0; i < numCars; i++) {
printf("%s\n%d %d %d\n", garage[i].license_plate, garage[i].parking_spot, garage[i].num_tickets, garage[i].time_left);
fprintf(outFilePtr, "%s\n%d %d %d\n", garage[i].license_plate, garage[i].parking_spot, garage[i].num_tickets, garage[i].time_left);
}
}
fclose(outFilePtr);
}
This is my input command.
./a.out 6 garage.txt output.txt
Here is what print in my terminal.
fi590dz 20 2 25
57fjgmc 8 0 55
7dkgjgu 25 1 15
f9e829d 1 2 60
4jgfd81 12 2 10
Segmentation fault: 11
By the way, I'm pretty new in programming and really bad with debugging. Could you give me some tips of how to debug or any debugging tools? I use a mac so gdb doesn't work.
Not a complete answer, because it’s a homework problem and you want to figure it out yourself, but here are some hints.
First, you really want to learn how to run your program in a debugger and get it to tell you which line crashed the program, and on which data.
Second, make sure you initialize the pointers for every element of the array before you try to read or write them.
Third, you’ll save yourself a lot of trouble if you initialize all your dynamic and local variables to zeroes, not garbage. It will make a lot of bugs reproducible, make a lot of bugs crash immediately instead of corrupting memory, and also make it obvious when you debug that you’re using uninitialized data.
Therefore, I suggest you get in the habit of allocating your dynamic arrays with calloc(), not malloc().
The problem lies within your parked_car = import_cars(argv[2], number); and Car* import_cars(char* filename, int numCars);functions.
Indeed in Car* import_cars(char* filename, int numCars); you are doing this:
Car inCar;
inCar.license_plate = (char*)malloc(sizeof(char) * 8);
So you are creating a local variable that is not accessible outside of the function (many different things can happen to the memory after the end of the function).
So when you do: parked_car = import_cars(argv[2], number); you are assigning to parked_car a freed variable.
A solution is to simply use the parked_caras an argument of your import_cars() function. All modifications made within the function will still be valid after it returns. So you should have:
void import_cars(char* filename, int numCars, Car* car);
For everyone who met the issue here, I found the problem in my program. The problem is that I didn't allocate space for each of the license_plate pointer in the structure. So my way to solve it is add a line as below in the for loop of the import_cars function.
inCar[i].license_plate = (char*)malloc(sizeof(char) * LICENSEPLATELENGTH);
I've a newbie question regarding freeing memory allocated for an array of struct.
This is the code:
typedef struct {
char code[6];
char name[31];
char cname[31];
int anno;
} cliente;
cliente *readcostumers(char*filename,int * dim) {
int i;
cliente *d;
cliente temp;
FILE*fp;
fp=fopen(filename,"r");
*dim=0;
//count the number of lines
while(fscanf(fp,"%s %s %s %d", temp.code, temp.name, temp.cname,&(temp.anno))==4)
(*dim)++;
rewind(fp);
//allocate "dim" struct
int ss = sizeof(cliente);
d = (cliente*)malloc(ss * (*dim));
cliente *currCli = d;
//assign lines to struct
for(i=0; i<*dim; i++) {
fscanf(fp,"%s %s %s %d",currCli->code, currCli->name, currCli->cname, &(currCli->anno));
currCli = currCli + ss;
}
fclose(fp);
return d;
}
This piece of code basically reads a text file, with any number of lines, formatted with a specific pattern and assign the contents to an array of strcut cliente.
This seems to work fine, except when i free the memory previous allocated:
int main () {
int x,i;
cliente *f = readcostumers("c:/temp/clienti.txt",&x);
int len = sizeof(cliente);
for(i=0; i<x; i++) {
printf("\n%s %s %s %d",(f + len*i)->code, (f + len*i)->name,
(f + len*i)->cname, (f + len*i)->anno);
}
free(f);
}
The last statement free(f) causes a SIGTRAP exception, altough the values printed are correct read from file.
The file content is this:
A3789 Paolo Rossi 2001
X478D Marcantonio Bianchi 2004
Where is the mistake?
When you increment currCli in readcostumers you should use 1 and in main you shouldn't multiply the index with len. These are taken care of by the language. These two errors are compensating each other, but in the mean time you are accessing outside the allocated memory and most likely overwriting internal administration of the heap allocation algorithms. Ultimately resulting in a crash in free.
Look into the valgrind tool as it finds these kind of errors flawlessly.
What are you doing here?
currCli = currCli + ss;
You should be incrementing the pointer by 1, not by the size of an element in the array you allocated. (The language automatically scales pointer additions by the size of the object pointed to.) This leads to writing outside the allocated area, which in turn leads to corrupted memory, and SIGTRAP or core dump or other similar problems.