I'm working on a client, server project. I receive a response from the server where I have to create two files. The first file is a .html file and the second file is .png file. I parse the response and I try to dynamically create the files in a while loop.
...
FILE *fwrp;
char *response = malloc(MAXDATASIZE * sizeof(char));
memset(response, '\0', sizeof(char) * MAXDATASIZE);
char *r = &response[0];
while (fread(field, sizeof(field), 1, fpr)) {
for (int i = 0; i < MAXDATASIZE; i++) {
*r = field[i];
r++;
//Some unecessary code...
if (strstr(response,"file=")){
char* newFileName = strchr(response, '=');
newFileName++;
fwrp = fopen(newFileName, "w");
data = false;
//...
I hope I didn't cut too much necessary information. The problem is the following: The files are created. Also with the right content.
The problem just the dynamic name of the file. One time the name should be ok.png, but instead it is 'ok.png'$'\n'
The same problem for the html file. The name should be example.html but is 'example.html'$'\n'
Already tried to print the names before they are created. They have the right format when they are printed. And I tried to allocate the memory with strdup, but it did not work for some reason. Anybody have an idea why this problem appears?
SOLUTION:
For those who are interested. Here is my solution
int receiveResponse(int sockfd) {
int sdw = dup(sockfd);
FILE *fpr = fdopen(sdw, "r");
FILE *fwrp;
int lenOfRecord = 0;
bool data = false;
bool status_checked = false;
bool first = true;
unsigned char field[MAXDATASIZE] = {0};
char *response = malloc(MAXDATASIZE * sizeof(char));
memset(response, '\0', sizeof(char) * MAXDATASIZE);
char *r = &response[0];
while (fread(field, sizeof(field), 1, fpr)) {
for (int i = 0; i < MAXDATASIZE; i++) {
*r = field[i];
r++;
if ((field[i] == '\n') && (data == false)){
if (strstr(response, "status=") && (status_checked == false)){
status_checked = true;
char* status = strchr(response,'=');
status++;
}
if (strstr(response, "len=")){
char *len = strchr(response, '=');
len++;
char *ptr;
lenOfRecord = strtol(len,&ptr,10);
data = true;
first = true;
}
if (strstr(response,"file=")){
char* tmp = strchr(response, '=');
tmp++;
char* newFileName = malloc(strlen(tmp) * sizeof(char));
memcpy(newFileName, tmp, strlen(tmp) * sizeof(char));
newFileName[strlen(newFileName) - 1] = 0;
fwrp = fopen(newFileName, "w");
free(newFileName);
data = false;
}
free(response);
char* response = malloc(MAXDATASIZE * sizeof(char));
memset(response, '\0', sizeof(char) * MAXDATASIZE);
r = &response[0];
}
if (--lenOfRecord == 0){
data = false;
fflush(fwrp);
fclose(fwrp);
}
if ((data == true) && (first == false)) {
fputc(field[i], fwrp);
}
if ((data == true) && (first == true)){
first = false;
}
}
}
}
So the problem was solved with this modification
newFileName[strlen(newFileName) - 1] = 0;
I've no idea, why are you copying readed field content into response instead of reading strictly into response. Additionaly, you didn't show the declaration of field.
Probably you should take the better care on count of readed chars (returned by fread()): it can be negative (means: error), not only positive or 0.
What about zero-termination?
So, my proposition is:
//...
// for better readability
#define MAX_RESPONSE_SIZE (MAXDATASIZE * sizeof(char))
// below: added 1 byte for preserving the proper string termination ('\0' byte)
#define RESPONSE_BUFFER_SIZE (MAXDATASIZE + 1)
FILE *fwrp;
char *response = malloc(RESPONSE_BUFFER_SIZE);
memset(response, '\0', RESPONSE_BUFFER_SIZE);
int readOffset = 0; // offset for reading the next chunk
int readCount; // count of readed characters/bytes
// below: return of fread() can be positive, 0 if no more data, or negative if error
while ((readCount = fread(response + readOffset, MAX_RESPONSE_SIZE - readOffset, 1, fpr)) > 0) {
readOffset += readCount;
}
//Some unecessary code...
if (strstr(response, "file=")) {
char* newFileName = strchr(response, '=');
newFileName++;
fwrp = fopen(newFileName, "w");
data = false;
//...
Related
I want to change specific word in a file which has given by the user in C. here is a part of my code. (b is the path of my file.)
When I wrote dosya = fopen(b,"w+"); I wanted it to read the old content, then delete it. Then the code starts and changes the word which doesn't have any problem. In the end I closed my file with fclose(dosya);. Then I wrote dosya = fopen(b,"a+"); so it can add the new version of the content. If I don't write "a+" and write "w+" it only gets one line of the code because in my main function I filled my file with fgets which is filling it line by line.
while ((fgets(a, 1000, dosya)) != NULL)
{
replaceWordInText(a,degis,son,b);
}
But if I try to fill it with fputs instead of fgets it doesn't fill. So I used fgets. When I use this code it works perfectly but then it deletes all my files in my university folder because it says it has some kind of virus I guess. What is the problem? What have I done wrong?
void replaceWordInText(const char *text, const char *oldWord, const char *newWord,char *b) {
FILE *dosya;
dosya = fopen(b,"w+");
int i = 0, cnt = 0;
int len1 = strlen(newWord);
int len2 = strlen(oldWord);
for (i = 0; text[i] != '\0'; i++) {
if (strstr(&text[i], oldWord) == &text[i]) {
cnt++;
i += len2 - 1;
}
}
char *newString = (char *)malloc(i + cnt * (len1 - len2) + 1);
i = 0;
while (*text) {
if (strstr(text, oldWord) == text) {
strcpy(&newString[i], newWord);
i += len1;
text += len2;
}
else
newString[i++] = *text++;
}
fclose(dosya);
dosya = fopen(b,"a+");
fputs(newString,dosya);
}
Following is a part of a file that needs to be parsed
record(ai, "SRC01-VA-IMG1:getPressure")
{
field(DESC, "Reads Cell SR-GC1 Pressure")
field(SCAN, "1 second")
field(DTYP, "stream")
field(INP, "#vacuum-XGS600-gc.proto getPressure(1) SR-GC1")
field(PINI, "YES")
field(VAL, "0")
field(PREC, "3")
field(LOLO, "") field(LLSV, "NO_ALARM")
field(HIGH, "") field(HSV, "NO_ALARM")
field(HIHI, "") field(HHSV, "NO_ALARM")
}
The parsing process will read the record name (In the qoutes) and type (ai, in the line record), and each field type and value (in any line that starts with field. e.g. Type: PINI, Value: "YES"). Note that each line can contain more than one record definition. The example contains some interesting cases like multiple fields on the same line, parenthesis inside qoutes, etc.
Here is my code for that purpose:
struct field
{
char* name;
char* value;
};
struct record
{
char* name;
char* type;
struct field* fields;
};
struct record* get_records(char* file, int* length)
{
size_t SIZE = 0;
size_t fSIZE = 1;
const int N = 100;
struct record* records = malloc(1 * sizeof(struct record));
struct field* fields;
// char line[N];
char* line = malloc(N);
char record_name[100];
char record_type[10];
char field_name[10];
char field_value[100];
char temp[100];
int open, close, comma, q1, q2;
FILE* fp = fopen(file, "r");
if(fp != NULL)
{
while(fgets(line, N, fp))
{
line = strtrim(line);
if(strncmp(line, "record", 6) == 0)
{
memset(record_name, 0, sizeof(record_name));
memset(record_type, 0, sizeof(record_type));
struct record* r = malloc(sizeof(struct record));
open = strchr(line, '(') - line + 1;
close = strchr(line, ')') - line + 1;
comma = strchr(line, ',') - line + 1;
q1 = strchr(line, '"') - line + 1;
q2 = strrchr(line, '"') - line + 1;
strncpy(record_type, &line[open], comma - open - 1);
strncpy(record_name, &line[q1], q2 - q1 - 1);
record_name[q2 - q1 - 1] = '\0';
record_type[comma - open - 1] = '\0';
r->name = record_name;
r->type = record_type;
printf("Name: %s\n", r->name);
printf("Type: %s\n", r->type);
fSIZE = 0;
fields = malloc(100 * sizeof(field)); // HERE
while(fgets(line, N, fp))
{
struct field* f = malloc(sizeof(struct field));
if(strncmp(line, "}", 1) == 0)
break;
if(strncmp(line, "{", 1) == 0)
continue;
line = strtrim(line);
int i1 = 0;
int i2 = 0;
char* p1 = strstr(line, "field");
char* p2;
while(p1 != NULL)
{
i1 = p1 - line;
p2 = strstr(p1 + 1, "field");
if(p2 != NULL)
{
i2 = p2 - line;
p1 = strstr(p1 + 1, "field");
}
else
{
i2 = strlen(line);
p1 = NULL;
}
memset(temp, 0, sizeof(temp));
memset(field_name, 0, sizeof(field_name));
memset(field_value, 0, sizeof(field_value));
strncpy(temp, &line[i1], i2 - i1); temp[i2-i1] = '\0';
printf("Line2 : %s\n", temp);
open = strchr(temp, '(') - temp + 1;
close = strrchr(temp, ')') - temp + 1;
comma = strchr(temp, ',') - temp + 1;
q1 = strchr(temp, '\"') - temp + 1;
q2 = strrchr(temp, '\"') - temp + 1;
strncpy(field_value, &temp[q1], q2 - q1 - 1); field_value[q2-q1-1] = '\0';
strncpy(field_name, &temp[open], comma - open - 1); field_name[comma-open-1] = '\0';
printf("Name : %s\n", field_name);
printf("Value: %s\n\n", field_value);
f->name = field_name;
f->value = field_value;
fields[fSIZE++] = *f;
}
free(line);
line = malloc(N);
}
r->fields = fields;
records[SIZE++] = *r;
}
else
continue;
}
}
else
{
printf("%s\n", "Unable to open file.");
exit(1);
}
*length = SIZE;
// fclose(fp);
return records;
}
int main()
{
int length = 0;
struct record* records = get_records("./test.db", &length);
// printf("Anything \n");
int i = 0;
for(i = 0; i < length; i++)
{
struct record* r = (struct record*) &records[i];
printf("Name: %s\n", r->name);
printf("Type: %s\n", r->type);
}
return 0;
}
Now I have two issues with this implementation which I could not figure out:
In the main function there is a printf statement, if uncommented the printf inside the loop will print garbage, otherwise correct output.
Having fclose in the function get_records uncommented gives a Segmentation fault (core dumped). With trial and error I figured out I either use it or use the malloc line designated by the comment HERE, for some reason using one of them or non the fault goes away. I understand I have something wrong with memory allocation somewhere, I used valgrind but it did not help me locating anything
Notes:
Constant numbers used in malloc are for testing purposes. We have files that contains 100's of records. This leads to a future question, which is better use large enough malloc buffer or use realloc?
Any other implementation in C, if any, is welcome :)
Seems like memory was massively messed up by this implementation due to many calls for malloc and free. What I did was to replace char* in the structs with arrays and line definition converted to char[] and dereference it in strtrim call.
I am trying to setup a local folder access from a c program by first initializing a string to the location the subsequently reading files from there. I'll also be required to write files in a similar manner eventually, but I am getting some strange bugs.
first the code:
resource_utils.h
static char* res_dir = NULL;
void clearnUpResourcePath(void);
char* getResource(char* filename);
char* readFile(char* file_path);
void writeFile(filename, File* file);
resource_utils.c
#include "resource_utils.h"
static char* getBasePath(void);
static void initResourcePath(void);
char* getResource(char* filename)
{
if(res_dir == NULL)
{
initResourcePath();
}
printf("res dir: %s || fn:%s\n",res_dir, filename);
char* str = (char*)malloc(sizeof(char) + strlen(res_dir) + strlen(filename));
memcpy(str, res_dir, strlen(res_dir)+1);
memcpy(str + strlen(res_dir), filename, strlen(filename));
str[(strlen(filename) + strlen(res_dir))] = '\0';
printf("resource filename:%s\n\n",str);
return str;
}
static void initResourcePath(void) {
char *base_path = getBasePath();
size_t len = strlen(base_path) + 22;
size_t i = 0;
size_t sz = 0;
char tmp[len];
while(base_path[i] != '\0')
{
if(base_path[i] == 'b' && base_path[i+1] == 'i' && base_path[i+2] == 'n')
{
sz = i;
}
tmp[i] = base_path[i];
i++;
}
char* b = strstr(tmp, "/bin");
memcpy(b, "/bin/resources/",15);
tmp[ sz + 14 ] = '\0';
res_dir = (char*)malloc(sizeof(char) * (sz + 4));
i = 0;
while(tmp[i] != '\0')
{
res_dir[i] = tmp[i];
i++;
}
res_dir[i] = '\0';
free(base_path);
}
void clearnUpResourcePath(void)
{
free(res_dir);
}
static char* getBasePath(void)
{
return "string to working directory"
}
char* readFile(char* file_path)
{
FILE* fp = fopen(file_path, "r");
if( fp == NULL )
{
perror("Error while opening the file.\n");
printf("failed to open file path:%s\n",file_path);
exit(EXIT_FAILURE);
}
size_t size = 1024;
char ch;
int index = 0;
char* line = (char*)malloc(sizeof(char) * size);
while( (ch = (char)fgetc(fp)) != EOF )
{
*(line+index) = ch;
++index;
if(index == size-1)
{
size = size * 2;
line = realloc(line, size);
printf("\nreallocing %zu\n",size);
}
line = realloc(line, (sizeof(char) * index) + 1);
*(line+index) = '\0';
}
//printf("sanity check\n\n%d\n\n",strlen(line));
//printf("final size: %lu for loading: %s\n",strlen(line), file_path);
fclose(fp);
return line;
}
This is basically suppose to setup this resource path once, keep it around for the lifetime of the program and free it before the program exits, but I get some strange results sometimes.
Take a look at this output
char* vshad = getResource("vert.shad");
char* fshad = getResource("frag.shad");
char* name = getResource("pal.ppm");
char* name1 = getResource("1234pal.ppm");
char* name2 = getResource("pal.ppm1234");
char* name3 = getResource("pal1.ppm");
char* name4 = getResource("pal.pp");
char* name5 = getResource("pal.ppdddddm");
char* name6 = getResource("pa");
res dir: /Users/username/DIRECTORY/project/build/bin/resources/ || fn:vert.shad
res dir len:48, filename len:9
resource filename:/Users/username/DIRECTORY/project/build/bin/resources/vert.shad
res dir: /Users/username/DIRECTORY/project/build/bin/resources/ || fn:frag.shad
res dir len:48, filename len:9
resource filename:/Users/username/DIRECTORY/project/build/bin/resources/frag.shad
res dir: /Users/username/DIRECTORY/project/build/bin/resources/FACETKEYS || fn:pal.ppm
res dir len:57, filename len:7
resource filename:/Users/username/DIRECTORY/project/build/bin/resources/FACETKEYSpal.ppm
res dir: /Users/username/DIRECTORY/project/build/bin/resources/FACETKEYS || fn:1234pal.ppm
res dir len:57, filename len:11
resource filename:/Users/username/DIRECTORY/project/build/bin/resources/FACETKEYS1234pal.ppm
res dir: /Users/username/DIRECTORY/project/build/bin/resources/FACETKEYS || fn:pal.ppm1234
res dir len:57, filename len:11
resource filename:/Users/username/DIRECTORY/project/build/bin/resources/FACETKEYSpal.ppm1234
res dir: /Users/username/DIRECTORY/project/build/bin/resources/FACETKEYS || fn:pal1.ppm
res dir len:57, filename len:8
resource filename:/Users/username/DIRECTORY/project/build/bin/resources/FACETKEYSpal1.ppm
res dir: /Users/username/DIRECTORY/project/build/bin/resources/FACETKEYS || fn:pal.pp
res dir len:57, filename len:6
resource filename:/Users/username/DIRECTORY/project/build/bin/resources/FACETKEYSpal.pp
res dir: /Users/username/DIRECTORY/project/build/bin/resources/FACETKEYS || fn:pal.ppdddddm
res dir len:57, filename len:12
resource filename:/Users/username/DIRECTORY/project/build/bin/resources/FACETKEYSpal.ppdddddm
res dir: /Users/username/DIRECTORY/project/build/bin/resources/FACETKEYS || fn:pa
res dir len:57, filename len:2
resource filename:/Users/username/DIRECTORY/project/build/bin/resources/FACETKEYSpa
loaded name:/Users/username/DIRECTORY/project/build/bin/resources/FACETKEYSpal.ppm?
the first two calls load properly but subsequent calls, especially if i change the length of the filename causes the code to break. I am not really sure.
I also noticed that the length of my res_dir changes which I really don't understand.
along with the accepted answer, here is my new code w/o magic numbers
static void initResourcePath(void)
{
char *base_path = getBasePath();
size_t len = strlen(base_path) *2; //making enough space
size_t i, sz = 0;
char tmp[len];
while(base_path[i] != '\0')
{
if(base_path[i] == 'b' && base_path[i+1] == 'i' && base_path[i+2] == 'n')
{
sz = i;
}
tmp[i] = base_path[i];
i++;
}
char* b = strstr(tmp, "/bin");
memcpy(b, "/bin/resources/",15);
tmp[ sz + 14 ] = '\0';
res_dir = (char*)malloc(sizeof(char) * (strlen(tmp) +1));
strcpy(res_dir, tmp);
free(base_path);
}
The problem you're having is here:
res_dir = (char*)malloc(sizeof(char) * (sz + 4));
You're not allocating enough space. You probably meant to use sz + 14 instead of sz + 4. That's one of the issues with using magic numbers as WhozCraig mentioned.
Rather than doing something convoluted like that, you know that you're copying tmp into res_dir, so do this instead:
res_dir = malloc(strlen(tmp)+1);
Note that the return value of malloc is not being casted. Doing so in C can hide subtle bugs if you fail to #include <stdlib.h>.
I'm reading in a .csv file, which I then need to parse into tokens. I tried using strtok(), but that unfortunately cannot return null fields (which my data is fulll of). So I went with a home-made version of strtok that I found, strtok_single, which returns the correct values that I need.
The data is input into my array correctly; but there is something wrong because before the initilization loops finish, the data gets overwritten. I've tried print statements and analyzing the problem but I just can't figure out what's wrong. Any insight at all would be helpful.
Here is the homemade strtok function I'm using:
char* strtok_single(char* str, char const* delims) {
static char* src = NULL;
char* p, *ret = 0;
if (str != NULL)
src = str;
if (src == NULL)
return NULL;
if ((p = strpbrk(src, delims)) != NULL) {
*p = 0;
ret = src;
src = ++p;
}
return ret;
}
Here is my code:
int main() {
int numLines = 0;
int ch, i, j;
char tmp[1024];
char* field;
char line[1024];
FILE* fp = fopen("filename.csv", "r");
// count number of lines in file
while ((ch = fgetc(fp)) != EOF) {
if (ch == '\n')
numLines++;
}
fclose(fp);
// Allocate memory for each line in file
char*** activity = malloc(numLines * sizeof(char**));
for (i = 0; i < numLines; i++) {
activity[i] = malloc(42 * sizeof(char*));
for (j = 0; j < 42; j++) {
activity[i][j] = malloc(100 * sizeof(char));
}
}
// read activity file and initilize activity matrix
FILE* stream = fopen("filename.csv", "r");
i = 0;
while (fgets(line, 1024, stream)) {
j = 0;
int newlineLoc = strcspn(line, "\n");
line[newlineLoc] = ',';
strcpy(tmp, line);
field = strtok_single(tmp, ",");
while (field != NULL) {
for (j = 0; j < 42; j++) {
activity[i][j] = field;
field = strtok_single(NULL, ",");
// when I print activity[i][j] here, the values are correct
}
// when I print activity[i][j] here, the values are correct for the
// first iteration
// and then get overwritten by partial data from the next line
}
i++;
} // close while
fclose(stream);
// by the time I get to here my matrix is full of garbage
// some more code that prints the array and frees memory
} // close main
activity[i][j] = field;
When the loops finish, each activity[i][j] points to somewhere in tmp, which is overwritten in each loop. Instead, since you pre-allocate space in each activity[i][j], you should just copy the contents of the string to that:
strcpy(activity[i][j], field);
Being careful of buffer overflow (i.e. if field is more than 99 characters).
Also, the sizeof(char) is superfluous since it's always 1 by definition.
Your line "activity[i][j] = field;" is backwards - you want the pointer assigned to the malloc'd memory.
I'm trying to learn C (which is freaking hard...) so I wanted to write a routine which gets a line of a file. I created this function :
int c;
int buflen = 100;
if((*buffer = malloc(sizeof(char) * buflen)) == NULL) {
DXLogWarn("Not enough memory");
return;
}
char * dst = *buffer;
char * end = *buffer + buflen - 1;
while ((c = getc(fp)) != EOF) {
if (c == '\n') {
break;
}
if (dst < end) {
*dst++ = c;
}
}
*dst = '\0';
Which works yay! But now I thought instead of cutting of the last part of the string I could realloc the buffer and continue till the '\n'. So I changed it to this:
void fget_line(FILE *fp, char **buffer) {
int c;
int buflen = 10;
if((*buffer = malloc(sizeof(char) * buflen)) == NULL) {
DXLogWarn("Not enough memory");
return;
}
char * dst = *buffer;
char * end = *buffer + buflen - 1;
while ((c = getc(fp)) != EOF) {
if (c == '\n') {
break;
}
if (dst < end) {
*dst++ = c;
} else {
buflen *= 2;
*buffer = realloc(*buffer, buflen * sizeof(char));
if (*buffer == NULL) {
DXLogError("Err");
return;
}
}
}
*dst = '\0';
}
Which gives me an error : malloc: * error for object 0x10a8001b8: incorrect checksum for freed object - object was probably modified after being freed.
* set a breakpoint in malloc_error_break to debug
Which I do not get. What am I doing wrong?
at the start you do:
char * dst = *buffer;
char * end = *buffer + buflen - 1;
This set dst and end to the correct positions inside buffer. Then you reallocate buffer:
*buffer = realloc(*buffer, buflen * sizeof(char));
This causes buffer to get a new value which is probably different then before. So you also have to update dst and end to the new positions inside buffer.
Changing end is easy, but because you keep changing dst, it is difficult to calculate the new value. So instead of changing the pointers, it might be easier to store just the offset in a integer. Something like:
int pos=0;
while ((c = getc(fp)) != EOF) {
if (c == '\n') {
break;
}
if (pos >= buflen-1) {
buflen *= 2;
*buffer = realloc(*buffer, buflen * sizeof(char));
if (*buffer == NULL) {
DXLogError("Err");
return;
}
}
(*buffer)[pos] = c;
pos++;
}
(*buffer)[pos] = '\0';
I also changed the if statement above, as you did not store the character which caused the reallocation.