How to read .cnf file (Conjunctive Normal Form) in C? - c

The file is shown below. I need to read them and store them in a data structure(may be a adjacency list). But I don't know how to ignore the the useless annotation and begin reading after 'p cnf'.
c This Formula is generated by mcnf
c
c horn? no
c forced? no
c mixed sat? no
c clause length = 3
c
p cnf 20 91
4 -18 19 0
3 18 -5 0
-5 -8 -15 0
-20 7 -16 0
10 -13 -7 0
...
That's my code, it may only work when there's no letters in the file.
// It would be the following code if the file starts with integers, but how could I change it if you were considering comments? I haven't debugged it yet so it might go wrong, I'll do it later.)
typedef struct LiteralNode {
int linum;
int tag; //When the variable is true, it is 1, else it is -1.
struct LiteralNode *next;
} LiteralNode;
typedef struct ClauseNode {
struct ClauseNode *next;
int No;
struct LiteralNode *info;
} ClauseNode;
typedef struct Clause {
int literal_num;
int clause_num;
ClauseNode *root;
} Clause;
Status CreateClause(Clause *cl, char *filename)
{
int m, i = 0;
ClauseNode *p, *q;
q = (ClauseNode*)malloc(sizeof(ClauseNode));
p = (ClauseNode*)malloc(sizeof(ClauseNode));
LiteralNode *l1,*l2;
p = cl -> root;
l1 = (LiteralNode*)malloc(sizeof(LiteralNode));
l2 = (LiteralNode*)malloc(sizeof(LiteralNode));
FILE *fp = fopen(filename, "rb");
if (fp == NULL) {
return ERROR;
}
fscanf(fp,"%d", &cl -> clause_num);
fscanf(fp, "%d",&cl -> literal_num);
while(fscanf(fp, "%d", &m) != EOF){
i++;
q -> No = i;
q -> next = NULL;
l1 -> linum = m;
l1 -> next = NULL;
q -> info = l1;
p -> next = q;
p = q;
fscanf(fp, "%d", &m);
while (m != 0) {
l2 -> linum = m;
l2 -> tag = 0;
l2 -> next = NULL;
l1 -> next = l2;
l1 = l2;
fscanf(fp, "%d", &m);
}
}
return OK;
}
data structureThe image is about the data structure I use to store the CNF.

You can iterate the lines: if a line begins with c or is empty: discard it. If it begins with p: parse the problem definition. If it begins with a number: switch to clause mode, and parse clauses without regard for line endings. C standard library facilitates it well.
Now, this is C, and C doesn't really come with good support for any complex data structures. Implementing data structures takes a lot of care! We'll start by implementing a "simple" dynamically-sized Clause type: something that, in C++, would be solved with std::vector<ClauseLiteral>. We need to pay lots of attention to error handling - otherwise the behavior of the program will be undefined, and we don't want that at all. We catch any arithmetic overflows ahead of time!
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
typedef int ClauseLiteral;
static const int ClauseLiteralMax = INT_MAX;
typedef struct Clause {
size_t size;
size_t capacity; // does not include the terminating zero
ClauseLiteral literals[1];
};
// Maximum capacity that doesn't overflow SIZE_MAX
static inline size_t Clause_max_capacity(void) {
return (SIZE_MAX-sizeof(Clause))/sizeof(ClauseLiteral);
}
static size_t Clause_size_for_(size_t const count_of_literals) {
assert(count_of_literals);
if (count_of_literals > Clause_max_capacity()) return 0;
return sizeof(Clause) + count_of_literals*sizeof(ClauseLiteral);
}
static size_t Clause_next_capacity_(size_t const capacity) {
assert(capacity);
const size_t growth_factor = 2;
if (capacity > Clause_max_capacity()/growth_factor) {
if (capacity < Clause_max_capacity()) return Clause_max_capacity();
return 0;
}
return capacity * growth_factor;
}
static Clause *new_Clause_impl_(size_t const capacity) {
size_t const alloc_size = Clause_size_for_(capacity);
assert(alloc_size);
Clause *const clause = calloc(alloc_size); // is zero-terminated
if (!clause) return NULL;
clause->size = 0;
clause->capacity = capacity;
return clause;
}
Clause *new_Clause(void) { return new_Clause_impl_(4); }
void free_Clause(Clause *clause) { free(clause); }
/** Assures that the clause exists and has room for at least by items */
bool Clause_grow(Clause **const clause_ptr, size_t by) {
assert(clause_ptr);
if (!*clause_ptr) return (*clause_ptr = new_Clause_impl_(by));
Clause *const clause = *clause_ptr;
assert(clause->size <= clause->capacity);
if (clause->size > (SIZE_MAX - by)) return false; // overflow
if (by > Clause_max_capacity()) return false; // won't fit
if (clause->size > (Clause_max_capacity() - by)) return false; // won't fit
size_t const new_size = clause->size + by;
assert(new_size <= Clause_max_capacity());
if (new_size > clause->capacity) {
size_t new_capacity = clause->capacity;
while (new_capacity && new_capacity < new_size)
new_capacity = Clause_next_capacity_(new_capacity);
if (!new_capacity) return false;
Clause *const new_clause = realloc(clause, Clause_size_for_(new_capacity));
if (!new_clause) return false;
*clause_ptr = new_clause;
}
*clause_ptr->literals[new_size] = 0; // zero-terminate
return true;
}
bool Clause_push_back(Clause **clause_ptr, ClauseLiteral literal) {
assert(clause_ptr);
assert(literal); // zero literals are not allowed within a clause
if (!Clause_grow(clause_ptr, 1)) return false;
(*clause_ptr)->literals[(*clause_ptr)->size++] = literal;
return true;
}
We now have a means of growing the clauses as we read them. Let's read, then!
#include <stdio.h>
typedef struct CNF {
size_t variable_count;
size_t clause_count;
Clause *clauses[1];
};
static inline size_t CNF_max_clause_count() {
return (SIZE_MAX-sizeof(CNF))/sizeof(Clause*);
}
static size_t CNF_size_for_(size_t const clause_count) {
if (clause_count >= CNF_max_clause_count()) return 0;
return sizeof(CNF) + clause_count * sizeof(Clause*);
}
static CNF *new_CNF(size_t variable_count, size_t clause_count) {
assert(variable_count <= ClauseLiteralMax);
size_t const cnf_size = CNF_size_fir(clause_count);
CNF *cnf = calloc(cnf_size);
if (!cnf) return NULL;
cnf->variable_count = variable_count;
cnf->clause_count = clause_count;
return cnf;
}
static void free_CNF(CNF *const cnf) {
if (!cnf) return;
for (Clause **clause_ptr = &cnf->clauses[0]; *clause_ptr && clause+ptr < &cnf->clauses[clause_count]; clause_ptr++)
free_Clause(*clause_ptr);
free(cnf);
}
static CNF *read_p_line(FILE *file) {
assert(file);
size_t variable_count, clause_count;
int match_count = fscanf(file, "p cnf %zd %zd", &variable_count, &clause_count);
if (match_count != 2) return NULL;
if (variable_count > ClauseLiteralMax) return NULL;
return new_CNF(variable_count, clause_count);
}
static bool read_c_line(FILE *file) {
assert(file);
char c = fgetc(file);
if (c != 'c') return false;
while ((c = fgetc(file)) != EOF)
if (c == '\n') return true;
return false;
}
static bool read_clauses(FILE *file, CNF *cnf) {
assert(file);
if (!cnf) return false;
size_t const variable_count = cnf->variable_count;
for (Clause **clause_ptr = &cnf->clauses[0]; clause_ptr < &cnf->clauses[clause_count];) {
int literal;
int match_count = fscanf(file, "%d", &literal);
if (match_count != 1) return false;
if (literal == 0) {
if (!*clause_ptr) return false; // We disallow empty clauses.
clause_ptr++;
}
else if (literal >= -variable_count && literal <= variable_count) {
if (!Clause_push_back(clause_ptr, literal)) return false;
}
else return false;
}
return true;
}
CNF *read_CNF(FILE *file) {
assert(file);
CNF *cnf = NULL;
for (;;) {
char const c = fgetc(file);
if (c == EOF) goto error;
if (isspace(c)) continue; // skip leading whitespace
if (ungetc(c, file) == EOF) goto error;
if (c == 'p' && !(cnf = read_p_line(file))) goto error;
else if (c == 'c' && !read_c_line(file)) goto error;
else if (isdigit(c)) break;
goto error;
}
if (!read_clauses(file, cnf)) goto error;
return cnf;
error:
free_CNF(cnf);
return NULL;
}
As you can see, the code is far from trivial, because it's library code that needs to be resilient and not have any undefined behavior at all. "Simple" things can be quite complicated in C. That's why, hopefully, you'd rather do this work in C++ if you can.

Related

C: Output difference between printf and vfprintf when using the exact same inputs

I'm trying to write a logger function that logs stuff to a file in a printf manner but, if enabled, it will also log to the console. I'm trying it out with a custom function that uses a custom string struct representing a number and transforms it into an actual number.
The main function:
#define MSG "0xab45cdef"
int main(){
String s;
stringInit(&s);
stringSetString(&s,MSG,sizeof(MSG));
stringPrint(&s);
logOut("\nTransforming to value\n");
int64_t v = parseValue(s);
logOut("\n");
logOut("\nResult %li \n", v);
}
My output log function
void logOut(const char *control_string, ...){
FILE *fp;
fp = fopen(LOG_OUTPUT,"ab+");
va_list argptr;
va_start(argptr,control_string);
vfprintf(fp,control_string,argptr);
#ifdef LOG_CONSOLE
printf(control_string,argptr);
#endif
va_end(argptr);
fclose(fp);
}
My String related functions
typedef struct {
char *s;
unsigned int size;
} String;
void stringInit(String *s){
s->s = NULL;
s->size = 0;
}
void stringAddChar(String *s, char c){
if (s->size > 0){
// Adding one more char.
s->s = (char *) realloc (s->s, (s->size + 1)*sizeof(char));
}
else{
// First char.
s->s = (char *) malloc(sizeof(char));
}
s->size++;
s->s[s->size-1] = c;
}
void stringFree(String *s){
if (s->size == 0) return;
free(s->s);
s->s = NULL;
s->size = 0;
}
void stringSetString(String *s, char *str, uint32_t nsize){
// Clearing the previous string.
stringFree(s);
for (uint32_t i = 0; i < nsize; i++){
// This avoids the extra char in a null terminated string.
if ((i == nsize-1) && (str[i] == 0)) break;
stringAddChar(s,str[i]);
}
}
void stringPrint(String *s){
for (uint32_t i = 0; i < s->size; i++){
logOut("%c",s->s[i]);
}
}
And finally the parseValue function
int64_t power(int64_t base, int64_t exp){
int64_t ans = 1;
for (int i = 0; i < exp; i++){
ans = ans * base;
}
return ans;
}
int64_t parseValue(String input){
int64_t base = 10;
int64_t res = 0;
int64_t maxpow = input.size-1;
uint32_t start = 0;
if (input.size > 0){
// Must check if it is hex or not.
if (input.s[0] == '0' && input.s[1] == 'x'){
base = 16;
start = 2;
maxpow = input.size-3;
}
}
for (int i = start; i < input.size; i++){
int64_t p = maxpow;
maxpow--;
char c = toupper(input.s[i]);
// printf("Char %d is %d\n",i,c);
int64_t v = c - 48;
if ((v >= 0) && (v <= 9)){
res = res + v*power(base,p);
}
else if ((c >= 65) && (c <= 70)){
if (base == 16){
v = c - 55;
res = res + v*power(base,p);
}
else{
logOut("Invalid char %c in a decimal number\n",c);
return -1;
}
}
else{
logOut("Invalid digit %d\n",c);
return -1;
}
}
return res;
}
Now when I run the main the console outputs:
pppppppppp
Transforming to value
Result 140726926743712
While my log.txt file has this
0xab45cdef
Transforming to value
Result 2873478639
The content of the log.txt file is correct. So why is the console output different?
To summarize, your logOut function has some mistakes. You can't "re-use" va_list after it has been used in another function. The function could look like this:
void logOut(const char *control_string, ...){
FILE *fp;
fp = fopen(LOG_OUTPUT,"ab+");
if (fp == NULL) {
abort();
}
va_list argptr;
va_start(argptr, control_string);
if (vfprintf(fp, control_string, argptr) < 0) {
// handle error
}
va_end(argptr);
fclose(fp);
#ifdef LOG_CONSOLE
va_start(argptr, control_string); // do not re-use va_list
vprintf(control_string, argptr);
// ^ you pass va_list
va_end(argptr);
#endif
}
Notes:
realloc(NULL, ...) is equal to malloc(...). So there is no need to if (s->size > 0){ inside stringAddChar - just call realloc(s->s, and make sure that s->s is NULL when size is zero.
Your code misses a lot of error handling. A proper way to handle realloc is to use a temporary pointer so that original memory will not leak: void *p = realloc(s->s, ...); if (p == NULL) { free(s->s); /* handle errors */ abort(); } s->s = p;.
Try not to use magic numbers in code. c - 48; is better written as c - '0';.

Manipulating structs with a void function in C

so I've been set a task of creating a faux string struct and implementing all the usual string functions on my faux string struct. I'm stuck on the tests of my strcat implementation called append, with the first test failing (segfault) being the 5th line. My function for creating new structs should be OK because it passed all the tests, but I've included it just incase.
I've already been able to successfully implement length, get, set and copy functions for my faux string structs.
The struct:
struct text {
int capacity;
char *content;
};
typedef struct text text;
My function for creating new structs:
text *newText(char *s) {
printf("new Text from %s\n", s);
int sizeNeeded = (strlen(s)+1);
int sizeGot = 24;
while (sizeNeeded > sizeGot) {
sizeGot = sizeGot * 2;
}
text *out = malloc(sizeGot);
char *c = malloc(sizeGot);
strcpy(c, s);
out->content = c;
out->capacity = (sizeGot);
printf("the capacity is %d\n", sizeGot);
return out;
free(c);
}
My append function:
void append(text *t1, text *t2) {
printf("t1 content is %s, t2 content is %d\n", t1->content, *t2->content);
int sizeNeeded = (t1->capacity + t2->capacity);
int sizeGot = 24;
while (sizeNeeded > sizeGot) {
sizeGot = sizeGot * 2;
}
char *stringy = calloc(sizeGot, 32);
stringy = strcat(t1->content, t2->content);
free(t1);
t1 = newText(stringy);
}
and finally the tests:
void testAppend() {
text *t = newText("car");
text *t2 = newText("pet");
append(t, t2);
assert(like(t, "carpet"));
assert(t->capacity == 24);
text *t3 = newText("789012345678901234");
append(t, t3);
assert(like(t, "carpet789012345678901234"));
assert(t->capacity == 48);
freeText(t);
freeText(t2);
freeText(t3);
}
You are allocating memory in the wrong way. You could fix this by using a flexible array member like this:
typedef struct {
int capacity;
char content[];
} text;
text *out = malloc(sizeof(text) + sizeof(something));
strcpy(out->content, str);
...
And obviously code such as this is nonsense:
return out;
free(c);
}
Enable compiler warnings and listen to them.
Och, some errors you have:
Inside text_new you allocate memory for text *out using text *out = malloc(sizeGot); when sizeGot = 24 is a constant value. You should allocate sizeof(*out) or sizeof(text) bytes of memory for it.
I don't know what for int sizeGot = 24; while (sizeNeeded > sizeGot) the loop inside text_new and append is for. I guess the intention is to do allocations in power of 24. Also it mostly looks like the same code is in both functions, it does look like code duplication, which is a bad thing.
Inside append You pass a pointer to t1, not a double pointer, so if you modify the t1 pointer itself the modification will not be visible outside of function scope. t1 = newText(stringy); is just pointless and leaks memory. You could void append(text **t1, text *t2) and then *t1 = newText(stringy). But you can use a way better approach using realloc - I would expect append to "append" the string, not to create a new object. So first resize the buffer using realloc then strcat(&t1->content[oldcapacity - 1], string_to_copy_into_t1).
int sizeNeeded = (t1->capacity + t2->capacity); is off. You allocate capacity in power of 24, which does not really interact with string length. You need to have strlen(t1->content) + strlen(t2->content) + 1 bytes for both strings and the null terminator.
Try this:
size_t text_newsize(size_t sizeNeeded)
{
// I think this is just `return 24 << (sizeNeeded / 24);`, but not sure
int sizeGot = 24;
while (sizeNeeded > sizeGot) {
sizeGot *= 2;
}
return sizeGot;
}
text *newText(char *s) {
printf("new Text from %s\n", s);
if (s == NULL) return NULL;
int sizeNeeded = strlen(s) + 1;
int sizeGot = text_newsize(sizeNeeded);
text *out = malloc(sizeof(*out));
if (out == NULL) {
return NULL;
}
out->content = malloc(sizeGot);
if (out->content == NULL) {
free(out);
return NULL;
}
strcpy(out->content, s);
out->capacity = sizeGot;
printf("the capacity is %d\n", sizeGot);
return out;
}
and this:
int append(text *t1, text *t2) {
printf("t1 content is %s, t2 content is %s\n", t1->content, t2->content);
int sizeNeeded = strlen(t1->content) + strlen(t2->content) + 1;
if (t1->capacity < sizeNeeded) {
// this could a text_resize(text*, size_t) function
int sizeGot = text_newsize(sizeNeeded);
void *tmp = realloc(t1->content, sizeGot);
if (tmp == NULL) return -ENOMEM;
t1->content = tmp;
t1->capacity = sizeGot;
}
strcat(t1->content, t2->content);
return 0;
}
Some remarks:
Try to handle errors in your library. If you have a function like void append(text *t1, text *t2) let it be int append(text *t1, text *t2) and return 0 on success and negative number on *alloc errors.
Store the size of everything using size_t type. It's defined in stddef.h and should be used to represent a size of an object. strlen returns size_t and sizeof also returns size_t.
I like to put everything inside a single "namespace", I do that by prepending the functions with a string like text_.
I got some free time and decided to implement your library. Below is the code with a simple text object storing strings, I use 24 magic number as allocation chunk size.
// text.h file
#ifndef TEXT_H_
#define TEXT_H_
#include <stddef.h>
#include <stdbool.h>
struct text;
typedef struct text text;
text *text_new(const char content[]);
void text_free(text *t);
int text_resize(text *t, size_t newsize);
int text_append(text *to, const text *from);
int text_append_mem(text *to, const void *from, size_t from_len);
const char *text_get(const text *t);
int text_append_str(text *to, const char *from);
char *text_get_nonconst(text *t);
size_t text_getCapacity(const text *t);
bool text_equal(const text *t1, const text *t2);
#endif // TEXT_H_
// text.c file
//#include "text.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
struct text {
size_t capacity;
char *content;
};
text *text_new(const char content[])
{
text * const t = malloc(sizeof(*t));
if (t == NULL) goto MALLOC_ERR;
const struct text zero = {
.capacity = 0,
.content = NULL,
};
*t = zero;
if (content != NULL) {
const int ret = text_append_str(t, content);
if (ret) {
goto TEXT_APPEND_ERR;
}
}
return t;
TEXT_APPEND_ERR:
free(t);
MALLOC_ERR:
return NULL;
}
void text_free(text *t)
{
assert(t != NULL);
free(t->content);
free(t);
}
int text_resize(text *t, size_t newcapacity)
{
// printf("%s %d -> %d\n", __func__, t->capacity, newcapacity);
// we resize in chunks
const size_t chunksize = 24;
// clap the capacity into multiple of 24
newcapacity = (newcapacity + chunksize - 1) / chunksize * chunksize;
void * const tmp = realloc(t->content, newcapacity);
if (tmp == NULL) return -ENOMEM;
t->content = tmp;
t->capacity = newcapacity;
return 0;
}
int text_append_mem(text *to, const void *from, size_t from_len)
{
if (to == NULL || from == NULL) return -EINVAL;
if (from_len == 0) return 0;
const size_t oldcapacity = to->capacity == 0 ? 0 : strlen(to->content);
const size_t newcapacity = oldcapacity + from_len + 1;
int ret = text_resize(to, newcapacity);
if (ret) return ret;
memcpy(&to->content[newcapacity - from_len - 1], from, from_len);
to->content[newcapacity - 1] = '\0';
return 0;
}
int text_append_str(text *to, const char *from)
{
if (to == NULL || from == NULL) return -EINVAL;
return text_append_mem(to, from, strlen(from));
}
int text_append(text *to, const text *from)
{
if (to == NULL || from == NULL) return -EINVAL;
if (text_getCapacity(from) == 0) return 0;
return text_append_str(to, text_get(from));
}
const char *text_get(const text *t)
{
return t->content;
}
const size_t text_strlen(const text *t)
{
return t->capacity == 0 ? 0 : strlen(t->content);
}
size_t text_getCapacity(const text *t)
{
return t->capacity;
}
bool text_equal_str(const text *t, const char *str)
{
assert(t != NULL);
if (str == NULL && t->capacity == 0) return true;
const size_t strlength = strlen(str);
const size_t t_strlen = text_strlen(t);
if (t_strlen != strlength) return false;
if (memcmp(text_get(t), str, strlength) != 0) return false;
return true;
}
// main.c file
#include <stdio.h>
int text_testAppend(void) {
text *t = text_new("car");
if (t == NULL) return -1;
text *t2 = text_new("pet");
if (t2 == NULL) return -1;
if (text_append(t, t2)) return -1;
assert(text_equal_str(t, "carpet"));
assert(text_getCapacity(t) == 24);
text *t3 = text_new("789012345678901234");
if (t3 == NULL) return -1;
if (text_append(t, t3)) return -1;
assert(text_equal_str(t, "carpet789012345678901234"));
assert(text_getCapacity(t) == 48);
text_free(t);
text_free(t2);
text_free(t3);
return 0;
}
int main()
{
text *t1 = text_new("abc");
text_append_str(t1, "def");
printf("%s\n", text_get(t1));
text_free(t1);
printf("text_testAppend = %d\n", text_testAppend());
return 0;
}

strcpy : how can i not copy \n [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
struct configurations *read_file(char * file_name)
{
FILE *f = fopen(file_name ,"r");
if(!f)
{
printf("**********Unable to open config.txt*********");
return NULL;
}
int i, prev, count;
char *line = NULL, buff[480] = {'\0'};
size_t len;
struct configurations *config = (struct configurations *) malloc(sizeof(struct configurations));
while (getline(&line,&len,f) != -1)
{
if(!strncmp("SERVERPORT = ",line,strlen("SERVERPORT = "))){
config->server_Port = atoi(strstr(line, " = ")+3);
}
else if(!strncmp("SCHEDULING = ",line,strlen("SCHEDULING = "))){
strcpy(config->sched,strstr(line, " = ") + 3);
}
By subctracting 1 from the length.
There are multiple simple and obvious improvements to your code
You should always check the return value before using from strstr().
strlen("SERVERPORT = ") is a very ugly way of writing 12, inefficient too.
You should use a little bit more white spaces to make the code readable.
Don't cast the return value of malloc() it only makes it more difficult to read and might hide a bug if you forget to include stdlib.h.
ALWAYS check if malloc() returned NULL before dereferencing the pointer.
Split every line at =, remove all surrounding white spaces from the 2 resulting values and then check which variable it is and assign the corresponding value.
As it is your code will fail if SERVERPORT=1234 for example, and even if it's ugly and spaces around the = operator are better, both should be valid unless of course you explicitly want the spaces.
Also by removing surrounding white spaces you ensure that any '\n' that was read by getline() will be removed from the value.
This is a quick API a wrote just now to show you how I would do it, of course every one has their own taste and ways to do things, but I hope it helps figuring out your mistakes
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
struct KeyValue {
char *key;
char *value;
};
struct KeyFile {
size_t size;
struct KeyValue *entries;
size_t count;
};
static struct KeyFile *
keyfile_new(void)
{
struct KeyFile *kf;
kf = malloc(sizeof(*kf));
if (kf == NULL)
return NULL;
kf->entries = malloc(10 * sizeof(*kf->entries));
if (kf->entries == NULL) {
kf->size = 0;
} else {
kf->size = 10;
}
kf->count = 0;
return kf;
}
static int
keyfile_add_value(struct KeyFile *kf, const char *const key, const char *const value)
{
struct KeyValue *entry;
if (kf->count + 1 >= kf->size) {
void *pointer;
pointer = realloc(kf->entries, (kf->size + 10) * sizeof(*kf->entries));
if (pointer == NULL)
return -1;
kf->entries = pointer;
kf->size += 10;
}
entry = &kf->entries[kf->count++];
entry->key = strdup(key);
entry->value = strdup(value);
return 0;
}
static void
keyfile_free(struct KeyFile *kf)
{
for (size_t i = 0 ; i < kf->count ; ++i) {
struct KeyValue *entry;
entry = &kf->entries[i];
free(entry->key);
free(entry->value);
}
free(kf->entries);
free(kf);
}
static struct KeyFile *
keyfile_read(const char *const path)
{
FILE *file;
struct KeyFile *kf;
size_t length;
char *line;
line = NULL;
length = 0;
file = fopen(path, "r");
if (file == NULL)
return NULL;
kf = keyfile_new();
if (kf == NULL)
return NULL;
while (getline(&line, &length, file) > 0) {
char *op;
char *key;
char *value;
op = strchr(line, '=');
if (op == NULL) {
fprintf(stderr, "malformed line!\n");
} else {
*op = '\0';
key = line;
while (isspace((unsigned char) *key) != 0)
++key;
value = op + 1;
op -= 1;
while (isspace((unsigned char) *op) != 0)
*(op--) = '\0';
while (isspace((unsigned char) *value) != 0)
value += 1;
op = value + strlen(value) - 1;
while (isspace((unsigned char) *op) != 0)
*(op--) = '\0';
if (keyfile_add_value(kf, key, value) != 0)
goto error;
}
}
fclose(file);
free(line);
return kf;
error:
keyfile_free(kf);
fclose(file);
free(line);
return NULL;
}
static void
keyfile_display(const struct KeyFile *const kf)
{
for (size_t i = 0 ; i < kf->count ; ++i) {
const struct KeyValue *entry;
entry = &kf->entries[i];
fprintf(stdout, "/%s/ => /%s/\n", entry->key, entry->value);
}
}
You could improve this to add lookup functions, to find specific values in the settings file. And you can make it a standalone library to use it in many projects too.

Memory leak in a recursive function in c

I need some help with memory leak in my C program. The following function searches a radix trie to find a word with a given number. It allocates some memory in every recursive call and I don't know how to sort it out so that the blocks allocated aren't lost. Please help.
char *substring(char *str, int position, int length) {
int c = 0;
char *sub = malloc(length*(sizeof(char))+1);
while (c < length) {
sub[c] = str[position + c];
c++;
}
return sub;
}
void prev(int w, int start, int end) {
char *newWord = "";
bool found = false;
void prevRec(struct tNode *t,
int w, int start, int end, char *soFar, int prevLength) {
if (t != NULL) {
char *updatedWord = malloc(strlen(soFar) + strlen(t->word));
strcpy(updatedWord,soFar);
strcat(updatedWord,t->word);
printf("%s\n", updatedWord);
int length = strlen(t->word);
if (t->count == w) {
found = true;
if ((start > -1) && (end <= strlen(updatedWord))) {
newWord = updatedWord;
} else {
newWord = "";
}
} else {
struct tNode *tmp = t->child;
struct tNode *tmp1 = NULL;
while ((tmp != NULL) && (!found)) {
prevRec(tmp,w,start,end,updatedWord,length);
tmp1 = tmp;
tmp = tmp->brother;
updatedWord = substring(updatedWord, 0, strlen(updatedWord) - prevLength);
}
}
}
}
prevRec(root,w,start,end,newWord,0);
printf("%s\n",newWord);
if (strlen(newWord) == 0) printf("ignored");
else {
char *tmp = substring(newWord,start,end - start + 1);
insert(tmp);
free(tmp);
}
You must free what you've allocated. In your case you could to sth. like that: replace
updatedWord = substring(updatedWord, 0, strlen(updatedWord) - prevLength);
by
char *sub = substring(updatedWord, 0, strlen(updatedWord) - prevLength);
free( updatedWord );
updatedWord = sub;
and add another
free( updatedWord );
as last line of your if( t != NULL ) block.
Besides as #Eregith has already mentioned in his comment, the '+1' for NULL is missing in the length you are allocating. And you should also add some error checking, as malloc() may return NULL

Uninitialised value was created by a heap allocation for allocation of an array of struct

Valgrind is complaining about a method and I really cannot figure out why. The error message I get is following:
==1664== Uninitialised value was created by a heap allocation
==1664== at 0x47F1: malloc (vg_replace_malloc.c:302)
==1664== by 0x100004B6A: filter_my_struct_list (main.c:3357)
==1664== by 0x100002C7C: main (main.c:370)
In the method he complains about I am just trying to "compress" a list, meaning, I am merging consecutive elements of my structure to one.
my_struct is just a structure with two int values:
typedef struct {
int start;
int len;
} my_struct;
And the method looks like:
my_struct* filter_my_struct_list(my_struct *listl, int *elements_in_list) {
my_struct *compressed_list;
if (*elements_in_list == 0) {
fprintf(stderr, "Number of my_structs should not be zero! Please check the input!\n");
exit(1);
} else if (*elements_in_list == 1) {
compressed_list = malloc(sizeof(my_struct)* 1);
my_struct f = {listl[0].start, listl[0].len};
compressed_list[0] = f;
return compressed_list;
}
int fst, remained_index;
remained_index = fst = 0;
compressed_list = malloc(sizeof(my_struct) * (*elements_in_list)); //<== The line valgrind doesn't like
while (fst < (*elements_in_list - 1)) {
int fst_in_loop = fst;
int nxt = fst_in_loop + 1;
BOOL terminate = FALSE;
while (!terminate) {
if (((listl[fst_in_loop].start + listl[fst_in_loop].len) == listl[nxt].start)) {
fst_in_loop++;
nxt++;
} else terminate = TRUE;
if (nxt == (*elements_in_list)) {
terminate = TRUE;
}
}
if (fst_in_loop != fst) {
int new_len = listl[fst_in_loop].start
+ listl[fst_in_loop].len - listl[fst].start;
my_struct f = {listl[fst].start, new_len};
compressed_list[remained_index] = f;
} else {
my_struct f = {listl[fst].start, listl[fst].len};
compressed_list[remained_index] = f;
}
remained_index++;
fst = nxt;
if (nxt == (*elements_in_list - 1)) {
if (fst == fst_in_loop) {
int f_1;
for (f_1 = fst; f_1 <= nxt; f_1++) {
my_struct f = {listl[f_1].start, listl[f_1].len};
compressed_list[remained_index] = f;
remained_index++;
}
} else {
my_struct f = {listl[nxt].start, listl[nxt].len};
compressed_list[remained_index] = f;
remained_index++;
}
}
}
*elements_in_list = remained_index;
return compressed_list;
}
Why is he telling me it is not initialised since I am catching the cases when there are less than two elements to be merged??
EDIT:
Ok i just found out, when I call only this method, the error disappears, but as soon as I reuse my list, the error appears

Resources