I write a function to insert some data to a file. And it works fine when i only use it once. but when i wrote a loop to test this function, the program crashed. how can i fix this?(sorry for my terrible English, i promise i will try to improve it^_^)
here is the code(written in C)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
int finsert(char *insert,int size,long offset,FILE *fp,int memory);
int main()
{
FILE *fp;
FILE *record;
char insert[100]="2";
long start,end;
int i=0;
if((fp=fopen("test","rb+"))==NULL)
{
printf("error!\n");
exit(1);
}
if((record=fopen("record.txt","w+"))==NULL)
{
printf("error!\n");
exit(1);
}
for(i=1;i<=10000;i+=1)
{
start=clock();
finsert(insert,strlen(insert),0,fp,i);
end=clock();
fprintf(record, "%d,%ld\n",i,end-start);
printf("\ri=%d ",i);
}
fclose(fp);
fclose(record);
return 0;
}
/*
this is the function and int memory is how many data to write to the file everytime
*/
int finsert(char *insert,int size,long offset,FILE *fp,int memory)
{
long i;
long getsize=size;
long writesize=size;
char *read;
char *write;
char *fill;
char *read_keep;
char *write_keep;
char *fill_keep;
long offset_read,offset_write;
if(size>=memory)
{
read=(char *) malloc(size);
write=(char *) malloc(size);
read_keep=read;
write_keep=write;
strcpy(write,insert);
while(getsize==size)
{
fseek(fp,offset,SEEK_SET);
getsize=fread(read,1,size,fp);
fseek(fp,offset,SEEK_SET);
fwrite(write,1,writesize,fp);
offset+=getsize;
strcpy(write,read);
writesize=getsize;
}
fwrite(write,1,writesize,fp);
free(read_keep);
free(write_keep);
}
else
{
writesize=memory;
getsize=memory;
offset_write=offset;
offset_read=offset-size+memory;
read=(char *) malloc(memory+3);
write=(char *) malloc(memory+3);
fill=(char *) malloc(memory-size);
for(i=0;i<memory+3;i+=1)
{
read[i]=0;
write[i]=0;
}
if(read==NULL||write==NULL||fill==NULL)
{
printf("malloc error!\n");
exit(1);
}
strcpy(write,insert);
fseek(fp,offset,SEEK_SET);
fread(fill,1,memory-size,fp);
strcpy(write+size,fill);
while(getsize==memory)
{
fseek(fp,offset_read,SEEK_SET);
getsize=fread(read,1,memory,fp);
fseek(fp,offset_write,SEEK_SET);
fwrite(write,1,writesize,fp);
offset_read+=getsize;
offset_write+=getsize;
if(memory+1<strlen(read)) printf("copy error!\n");
strcpy(write,read);
writesize=getsize;
}
fwrite(write,1,writesize,fp);
free(read);
free(write);
free(fill);
}
}
maybe you could describe a bit more what your program is intended to do.
When I run it in valgrind, it reported quite a lot invalid memory reads and writes...
The fact is that it runs fine once, because after one run program is not able to destroy its memory so much, however if you run it 10000 time, damage is severe (causing SEGFAULT).
Most of memory overwrites happens here:
strcpy(write+size,fill);
and here:
strcpy(write,insert);
strcpy(write,read);
caused by:
read=(char *) malloc(size);
write=(char *) malloc(size);
I was not able to determine why it happens in first case, but in second case it looks to be obvious that parameter size will always be 1 byte and you need to least 2 bytes for copy string, as ti must be terminated by '\0'.
so might to change the code to something like:
read=(char *) malloc(size + 1);
write=(char *) malloc(size + 1);
And for following code:
for(i=0;i<memory+3;i+=1)
{
read[i]=0;
write[i]=0;
}
You might have a look on memset().
P.S
I was able to make it run removing last free(read); but this is hardly correct solution ...
Related
I am processing *.fastq.gz file, something like the below:
#NB501139:187:H2Y5LBGXB:1:11101:17094:1060 2:N:0:CTTTGCGG
AGAGGATCCGTGTGANANNNGANNNCNNCCGNCTNNTANNAGATCACTTAGNNANNNNACAGCAGAAAANNNNNNNNNACAAGGTTGAAANTNTNTNN
+
A/AA///E/////EE#A###//###A##EEE#AE##EA##EE//<AE<EE<##/####/EE</EAE<//#########/E///</EE<<<#E#A#E##
#NB501139:187:H2Y5LBGXB:1:11101:3442:1060 2:N:0:CTTTGCGG
ACTGAGTCACGCACCNANNNCCNNNCNGCCGNCANNGCNNTGCACCGGTGGNCTNNNNTGTGTACTGAGNNTNNNNNNCATGCACACAGANTNCTCNN
+
AAAAAEEEEE/EEE6#<###EE###E#EEE/#AE##<E##EEEEEE/EEEA#EE####EAEEEEEEE/<##A######EEE/E<E/EEE/#A#AEA##
The file could be larger than RAM, so I process it block by block using file streaming, then output the result. By block, I mean 4 lines are a block.
#include <stdio.h>
#include <zlib.h>
#define MAX_LINE_LENGTH 128
typedef struct fastq
{
char *id;
char *seq;
char *qual;
} fastq;
fastq *get_fastq(gzFile file)
{
fastq *out = (fastq *)malloc(sizeof(fastq));
out->id = (char *)malloc(MAX_LINE_LENGTH);
out->seq = (char *)malloc(MAX_LINE_LENGTH);
out->qual = (char *)malloc(MAX_LINE_LENGTH);
char temp[MAX_LINE_LENGTH];
if (gzgets(file, out->id, MAX_LINE_LENGTH) != NULL)
{
gzgets(file, out->seq, MAX_LINE_LENGTH);
gzgets(file, temp, MAX_LINE_LENGTH);
gzgets(file, out->qual, MAX_LINE_LENGTH);
}
else
{
free_fastq(out);
return NULL;
}
return out;
}
To limit the I/O calling, I am looking for a way to read 4 lines at a time rather than calling gzgets() 4 times for one block. I'm unsure if this will save time; any suggestion is welcome.
When i try run with the reviews.csv file the code gives segmention
fault don't know why!! Can someone HELP me with that... In
guião1v2.h only are the structs made for this. In the code i add
some comments for being much easier understand what i'm doing.
I don't know how to fix this!!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "guião1v2.h"
#define COUNT 1024
#define MAX_LINE 10000000 //random num (the files given are big)
int main(int arg , char*argv[]){
int i = 0;
char buffer[COUNT];
char *buffer2 = malloc(COUNT);
User *user = malloc(sizeof(User)*MAX_LINE);
Review *reviews = malloc(sizeof(Review)*MAX_LINE);
//i do the allocation of memory.
FILE *files;
files = fopen(argv[1],"r"); //opening the file
if(files == NULL)
{
printf("Failed to open file");//in case of fail to open the file
exit(1);
}
if(strcmp(argv[1], "reviews.csv") == 0)
{
while (fgets(buffer2,COUNT,files))//trying to pass from the file to the struct
{
reviews[i].id = strdup(strsep(&buffer2,";"));
reviews[i].user_id =strdup(strsep(&buffer2,";"));
reviews[i].business_id =srdup(strsep(buffer2,";"));
reviews[i].stars = atof(strsep(&buffer2,";"));
reviews[i].useful = atoi(strsep(&buffer2,";"));
reviews[i].funny = atoi(strsep(&buffer2,";"));
reviews[i++].cool = atoi(strsep(&buffer2,";"));
}
for(int j=0; j < i-1; j++)//testing if the data was well copied.
{
printf("%s", reviews[j].id); //param
printf("%s", reviews[j].user_id); //param
printf("%s", reviews[j].business_id); //param
printf("%f", reviews[j].stars); //param
printf("%d", reviews[j].useful); //param
printf("%d", reviews[j].funny);
printf("%d", reviews[j].cool);
printf("\n");
}
}
fclose(files); // When i don't need the file i close it
free(user);//I give free to the memory
free(reviews);// Same thing
free(buffer2);
return 0;
}
Segmentation faults occurs only incase there are some memory issues. The code above uses command line argument as well as dynamic allocation through malloc.
I suggest remove the command line arguments from main() to make the code looks simpler. The problem here related to memory so try to specify memory statically not dynamically using malloc(),calloc() etc.
it's my first post so I apologize in advance if I've posted the code format wrong.
I've been trying to work out where I'm going wrong here for awhile now and haven't been able to find an answer. I keep getting a segmentation fault after two Lines of a text file have been scanned into my arrays. Text file follows the pattern of : City1 City2 distance.
I feel like it has something to do with the memory but I can't understand why.
#include <stdio.h>
#include <stdlib.h>
#include <string.h> //Chosen to use this library to break text file down.
#include "list.h" //Using file created in lab 3 earlier this year.
#define DYNAMIC_RESIZE 0 ///Might not be needed...
#define Max_Lines 40
#define LINE_SIZE 150
int main()
{
FILE *Distances_File = fopen("Distances.txt", "r");
char *City1[Max_Lines];
char *City2[Max_Lines];
int *Distances[Max_Lines];
City1[Max_Lines] = malloc(sizeof(Max_Lines));
City2[Max_Lines] = malloc(sizeof(Max_Lines));
Distances[Max_Lines] = malloc(sizeof(Max_Lines));
char File_Line[LINE_SIZE];
int Line_Count = 0;
if (!Distances_File) {
printf("File could not open");
return 1;
}
if ( Distances_File != NULL )
{
///Intro to the program.
printf("This is a program that will calculate the shortest distance between selected \ncities.");
printf("\nSo wish me luck :(\n \n");
while(fgets(File_Line, sizeof(File_Line), Distances_File))
{
//printf("%s", File_Line);
sscanf(File_Line, "%s%s%s", City1[Line_Count], City2[Line_Count], Distances[Line_Count]);
///Still issue of Distances being a char.
printf("%s\n%s\n%s\n\n", City1[Line_Count], City2[Line_Count], Distances[Line_Count]);
Line_Count++;
printf("%d", Line_Count);
}
}
}
This statement
char *City1[Max_Lines];
declare an array of char pointers and the size of the array is Max_Lines.
And here you are allocating memory to an invalid index of the array:
City1[Max_Lines] = malloc(sizeof(Max_Lines));
Max_Lines value is 40, so the valid index of the array of size Max_Lines will be 0-39.
You need to allocate memory to all the pointers of array City1 and City2 before using them.
May you write a function to perform this allocation, like this:
void allocate_city_mem(char *arr[], size_t sz) {
for(size_t i = 0; i < sz; i++) {
arr[i] = malloc(LINE_SIZE);
if (NULL == arr[i])
exit(EXIT_FAILURE);
}
}
In doing so, you need to make sure to free the dynamically allocated memory once you have done with it. You can do:
void free_city_mem(char *arr[], size_t sz) {
for(size_t i = 0; i < sz; i++) {
free(arr[i]);
arr[i] = NULL;
}
}
In your program, I can see that the Max_Lines and LINE_SIZE are small values, so as an alternative you can do this:
char City1[Max_Lines][LINE_SIZE];
With this, you don't need to take care of any allocation/deallocation of memory.
Also, no need to take the array of integer pointer for storing distance. Distances could be an array of integers.
In your code, you are calling fopen() and checking the return value of it (if (!Distances_File) {....) somewhere below in the code after calling malloc. As a good programming practice, you should immediately check the return value of library function in such cases because if they fail, there is no point in proceeding further.
Also, when using scanf family functions, make sure that format specifier corresponding to the parameter passed should be correct.
Collectively all above points, the main() will be something like this:
int main() {
FILE *Distances_File = fopen("Distances.txt", "r");
if (!Distances_File) {
printf("File could not open");
return 1;
}
char City1[Max_Lines][LINE_SIZE];
char City2[Max_Lines][LINE_SIZE];
int Distances[Max_Lines];
char File_Line[LINE_SIZE];
int Line_Count = 0;
//Intro to the program.
printf("This is a program that will calculate the shortest distance between selected \ncities.");
printf("\nSo wish me luck :(\n \n");
while(fgets(File_Line, sizeof(File_Line), Distances_File)) {
printf("Line number : %d\n", Line_Count+1);
//printf("%s", File_Line);
sscanf(File_Line, "%s%s%d", City1[Line_Count], City2[Line_Count], &Distances[Line_Count]);
///Still issue of Distances being a char.
printf("%s\n%s\n%d\n\n", City1[Line_Count], City2[Line_Count], Distances[Line_Count]);
Line_Count++;
}
return 0;
}
You have undefined behavior accessing City1[Max_Lines] where the size of the array is Max_Lines. You should change it instead allocate memory and make those pointers point to it. So you will do something like this:-
#define MAXLEN 100
...
for(size_y i = 0; i < Max_Lines; i++){
City1[i] = malloc(MAXLEN);
/* check malloc return value */
}
And also here you can simply do this too,
char City1[Max_Lines][MAXLEN];
Because here if you want to get MAXLEN byte buffer then instead of dynamic allocation you can do this. The only problem is that if Max_lines and MAXLEN is larger then there is a possibilty of constrained by stack size. Then dynamic allocation will be a rescue.
Also you should check the return value fopen. There are cases when fopen fails. You need to handle those cases separately.
try below variant:
#include <stdio.h>
#include <stdlib.h>
#include <string.h> //Chosen to use this library to break text file down.
//#include "list.h" //Using file created in lab 3 earlier this year.
#define DYNAMIC_RESIZE 0 ///Might not be needed...
#define Max_Lines 40
#define LINE_SIZE 150
typedef struct {
char data[LINE_SIZE];
} LineBuffer;
int main()
{
FILE *Distances_File = fopen("Distances.txt", "r");
LineBuffer *City1;
LineBuffer *City2;
int *Distances;
char File_Line[LINE_SIZE];
int Line_Count = 0;
City1 = (LineBuffer *)malloc(sizeof(LineBuffer)*Max_Lines);
City2 = (LineBuffer *)malloc(sizeof(LineBuffer)*Max_Lines);
Distances = (int *)malloc(Max_Lines);
if (!Distances_File) {
printf("File could not open");
return 1;
}
if ( Distances_File != NULL ) {
///Intro to the program.
printf("This is a program that will calculate the shortest distance between selected \ncities.");
printf("\nSo wish me luck :(\n \n");
while(fgets(File_Line, sizeof(File_Line), Distances_File) && Line_Count < Max_Lines)
{
//printf("%s", File_Line);
sscanf(File_Line, "%s%s%d", City1[Line_Count], City2[Line_Count], Distances[Line_Count]);
///Still issue of Distances being a char.
printf("%s\n%s\n%d\n\n", City1[Line_Count], City2[Line_Count], Distances[Line_Count]);
Line_Count++;
printf("%d", Line_Count);
}
}
free(City1);
free(City2);
free(Distances);
}
edit
sizeof(int) should be 4 bytes so malloc(sizeof(Max_Lines)) will allocate 4 bytes
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'm using this code to read a file into a buffer. The file is full of structs of evaluacion type (including some char and int variables).
Now I have the whole file in a buffer, how can I find the values of one variable in the buffer now?
For example buf.notamedia < 4. There are supposed to be many of them inside the file.
#include <unistd.h>
#include <sys/stat.h>
int revisanotas(int fd)
{
int nbytes = 1;
int nbytese = 0;
evaluacion buf;
struct stat datos;
fstat(fd, &datos);
printf("Size of file = %d \n", datos.st_size);
char *buffer = (char *)malloc(datos.st_size);
int actual = read(fd, buffer, datos.st_size);
printf("actual = %d\n", actual);
if (buf.notamedia >= 4.5 && buf.notamedia < 5)
{
/* ... */
}
}
Any idea is very welcome
I'm doing as you said, but I'm only getting one iteration, I don't know what I'm doing wrong :(
evaluacion* buffer=(evaluacion*)malloc(datos.st_size);
int actual = read(fd,buffer,datos.st_size);
printf("Number of structs = %d", (datos.st_size/(sizeof(evaluacion))));
for (i=0;i<(datos.st_size/(sizeof(evaluacion)));i++);
{
printf("Notamedia = %f\n",buffer[i].notamedia);
if (buffer[i].notamedia >= 4.5 && buffer[i].notamedia < 5)
{
printf("Notamedia = %f\n",buffer[i].notamedia);
}
{
}
}
}
Easiest to define the buffer as a pointer to the data structure and use that to dereference the data (although you should ensure the file size is a multiple of the structure size).
i.e.
evaluacion* buffer = (evaluation*)malloc(datos.st_size);
if(buffer[0].notamedia >= 4.5)
You can then increment the index to access other structures you loaded.
Thanks for the comments, I think I solved the problem, I modified the code:
#include <unistd.h>
#include <sys/stat.h>
int revisanotas(int fd)
{
int nbytes=1;
int nbytese=0;
int i=0;
int n=0;
struct stat datos;
fstat(fd, &datos);
evaluacion buf;
printf("File size = %d \n", datos.st_size);
evaluacion* buffer=(evaluacion*)malloc(datos.st_size);
int actual = read(fd,buffer,datos.st_size);
do
{
i++;
if (buffer[i].notamedia >= 4.5 && buffer[i].notamedia < 5)
{
n=n+1;
/*printf("Notamedia = %f\n",buffer[i].notamedia);
*/
buffer[i].notamedia=5;
}
}while (i<(datos.st_size/(sizeof(evaluacion))));
nbytese=write(fd,buffer,datos.st_size);
printf("Written bytes = %d\n",nbytese);
return(n);
}
Now, If the condition is matched, I'm modifying the buffer. Once I read all the structs I write the file in the disk again, but I still have a problem, every time, instead of write the file in the same position, seems like I'm adding the same information after the old one, so if I read the file once I get 3.5Mb, two times 7MB and so on :S.
Any idea what can I do?
Thanks