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

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.

Related

How to read .cnf file (Conjunctive Normal Form) in 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.

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;
}

How to fix copy of struct to array of structs segfault

I have the following two structs:
typedef struct {
char* key;
char* value;
} kvpair;
typedef struct {
kvpair ** array;
size_t length;
} kvarray;
And I want to copy new key and value pairs to the kvarray. I use realloc to allocate memory for each new item to be added to the kvpair array but struggling to work out how to copy the key and value.
If I do it like this:
kvs->array resized using realloc
// *** get segfault here!!! how to fix ***
kvs->array[kvs->length]->key = key;
kvs->array[kvs->length]->value = value;
But if I allocate memory separately for a kvpair* and do this way:
kvpair* kvp = malloc(sizeof(kvpair));
// copy key and value
// This below then works
kvs->array[kvs->length] = kvp;
// but there is a memory leak - or seems to be double allocation of memory for same thing
How to do this correctly?
The code is below (see // * get segfault here!!! how to fix * comment)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct {
char* key;
char* value;
} kvpair;
typedef struct {
kvpair ** array;
size_t length;
} kvarray;
kvarray * readKVs(const char** array, size_t length);
void freeKVs(kvarray * pairs);
int main() {
const char* things[] = { "wood=brown\n", "brick=red\n",
"grass=green", "hedge=green", "leaf=green" };
const size_t sz = sizeof(things) / sizeof(things[0]);
kvarray* kvs = readKVs(things, sz);
freeKVs(kvs);
}
kvarray * readKVs(const char** array, size_t length) {
kvarray* kvs = NULL;
for (size_t i = 0; i < length; ++i) {
const char* line = array[i];
if (kvs == NULL) {
kvs = malloc(sizeof(kvarray));
kvs->length = 0;
kvs->array = NULL;
}
char * found = strchr(line, '=');
if (found == NULL) {
// skip to next line
continue;
}
size_t len = strlen(line);
size_t pos = found - array[i];
char* value = NULL;
if (len > (pos + 1)) {
// non-blank value
// length of value is len - pos
value = malloc(len - (pos + 1));
strncpy(value, &line[pos + 1], (len - (pos + 1)) - 1);
// null terminate string
value[len - (pos + 1) - 1] = '\0';
printf("value:'%s'\n", value);
}
char* key = malloc(found - line + 1); // +1 for null terminator
strncpy(key, line, pos);
// remember strncpy bug!
key[found - line] = '\0'; // ensure null termination.
printf("key:'%s', length=%lu\n", key, strlen(key));
/*
// if I allocate an individual pair, then I am duplicating memory so should have to do this below
kvpair* kvp = malloc(sizeof(kvpair));
//kvpair kvp = {NULL, NULL};
printf("about to assign kvs->key = key\n");
kvp->key = key;
printf("about to assign kvs->value = value\n");
kvp->value = value;
*/
kvs->array = realloc(kvs->array, (kvs->length + 1) * sizeof(kvpair*));
// I want to be able to do this 2 lines below - but crashes
// *** get segfault here!!! how to fix ***
kvs->array[kvs->length]->key = key;
kvs->array[kvs->length]->value = value;
kvs->length++;
printf("kvs->length now=%lu\n", kvs->length);
}
return kvs;
}
void freeKVs(kvarray * pairs) {
if (pairs == NULL) {
return;
}
for (size_t i = 0; i < pairs->length; ++i) {
free(pairs->array[i]->key);
free(pairs->array[i]->value);
free(pairs->array[i]);
}
free(pairs);
}
When you do
kvs->array = realloc(kvs->array, (kvs->length + 1) * sizeof(kvpair*));
the contents of the new memory allocated will be indeterminate, it's not initialized. That means the next line
kvs->array[kvs->length]->key = key;
you will dereference an invalid pointer kvs->array[kvs->length]. That of course will lead to undefined behavior.
The solution is of course to make kvs->array[kvs->length] point somewhere valid, for example by doing
kvs->array[kvs->length] = malloc(sizeof(kvpair));

Segmentation Fault: double free or corruption (fast top)

I've a problem when I run this piece of code: a Segmentation Fault that appears during the free instruction of percorso. I cannot find the problem.
void ricerca(char nome[], struct node *radice, char percorso[], struct stringhe **indice) {
struct node *punt = radice;
int dim = len(percorso);
char *prov = NULL;
if (dim > 0) {
prov = malloc(2 * dim * sizeof(char));
prov[0] = '\0';
strcpy(prov, percorso);
free(percorso); //--------------------->here the SegFault
}
struct stringhe *nuovo = NULL;
int i = 0, fine = 0;
char *perc_orig = NULL;
if (punt != NULL) {
if (punt->array != NULL) {
dim = len(prov) + len(punt->nome) + 2;
percorso = malloc(dim * sizeof(char));
percorso[0] = '\0';
if (prov!=NULL)
strcpy(percorso, prov);
strcat(percorso, "/");
strcat(percorso, punt->nome);
perc_orig = malloc(dim * sizeof(char));
for (i = 0; i < N; i++) {
if (punt->array->vet[i] != NULL) {
perc_orig[0] = '\0';
strcpy(perc_orig, percorso);
ricerca(nome, punt->array->vet[i], perc_orig,indice);
}
}
free(perc_orig);
}
if (strcmp(nome,punt->nome) == 0) {
free(percorso);
dim = len(prov) + len(punt->nome) + 2;
percorso = malloc(dim * sizeof(char));
inizializza(percorso, dim);
if (prov != NULL)
strcpy(percorso, prov);
strcat(percorso, "/");
strcat(percorso, punt->nome);
nuovo = malloc(sizeof(struct stringhe));
nuovo->next = NULL;
nuovo->str = malloc(dim * sizeof(char));
inizializza(nuovo->str, dim);
strcpy(nuovo->str, percorso);
nuovo->next = (*indice);
*indice = nuovo;
}
while (punt->chain != NULL && fine == 0) {
ricerca(nome, punt->chain,prov, indice);
fine = 1;
if (prov!=NULL)
free(prov);
}
}
}
The len function is like strlen, but the difference is that I've made it myself.
the context is:
void find(char nome[], struct node *radice) {
char *perc = NULL;
struct stringhe **inizio = NULL;
inizio = malloc(sizeof(struct stringhe*));
*inizio = NULL;
int i = 0;
for (i = 0; i < N; i++) {
if (radice->array->vet[i] != NULL) {
perc = NULL;
ricerca(nome, radice->array->vet[i], perc, inizio);
}
}
if (*inizio != NULL) {
insertion(inizio);
stampap(*inizio);
} else
printf("no\n");
}
And the data structures:
struct tab {
struct node *vet[64];
};
struct node {
char nome[255];
int num;
int tipo;
char *dati;
struct tab *array;
struct node *chain;
};
This is really weird:
if (some condition)
free(percorso);
Later on we have:
perc_orig = malloc(dim*sizeof(char));
for(something){
if(something){
ricerca(nome,punt->array->vet[i],perc_orig,indice);
}
}
free(perc_orig);
If that if conditions happens, perc_orig will be freed twice. Kaboom.
I think your problem is you think that ricerca(..., char percico[], ...) copies percico. It doesn't; it's really ricerca(..., char *percico, ...) so you ended up freeing the memory twice.
the sizing for the char arrays needs to allow for the trailing NUL ('\0') character.
ALL fields that are referenced by strcpy() and similar functions need to have ALL source character arrays NUL terminated.
The code does not seem to be allocating enough room for those trailing NUL bytes NOR terminating every character array with a NUL char.
Segmentation fault occurs when you initialize a character pointer to NULL and try to point it to a not null value
For example,
char *a=NULL;
a='a';
Will cause segmentation fault. To avoid this you can try to initialize as,
char *a;
a='a';

Simple Shell in C [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I am working on a school project which is basically creating a simple shell in UNIX.
But I'm stuck with history part of my project.The explanation which is about history part is explained below:
history – This command is for maintaining a history of commands previously issued.
o history - print up to the 10 most recently entered commands in your shell.
o ! number - A user should be able to repeat a previously issued command by
typing ! number, where number indicates which command to repeat.
Note that ! 1 is for repeating the command numbered 1 in the list of commands returned by
history, and ! -1 is for repeating the last command.
And my code till history part is here :
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <limits.h>
#include <malloc.h>
#include <string.h>
#include <termios.h>
#include <errno.h>
#define CREATE_FLAGS (O_WRONLY | O_CREAT | O_APPEND)
#define CREATE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
#define CREATE_FLAG (O_WRONLY| O_CREAT| O_TRUNC)
#define MAXCHARNUM 128
#define MAXARGNUM 32
char *argsexec[MAXARGNUM];
char str[MAXCHARNUM];
char *path;
char *name;
struct Node
{
pid_t pid;
char *pname;
int index;
struct Node *nextPtr;
};
typedef struct Node Node;
typedef struct Node *NodePtr;
NodePtr list = NULL;
void addJob(NodePtr *currentPtr, pid_t pid, char *name, int indx)
{
NodePtr newPtr, prePtr, curPtr;
newPtr = malloc(sizeof(Node));
if (newPtr != NULL )
{
newPtr->pid = pid;
newPtr->pname = name;
newPtr->index = indx;
newPtr->nextPtr = NULL;
prePtr = NULL;
curPtr = *currentPtr;
while (curPtr != NULL )
{
prePtr = curPtr;
curPtr = curPtr->nextPtr;
}
if (prePtr == NULL )
{
newPtr->nextPtr = *currentPtr;
*currentPtr = newPtr;
}
else
{
prePtr->nextPtr = newPtr;
newPtr->nextPtr = curPtr;
}
}
}
void printJob(NodePtr curPtr)
{
if (curPtr == NULL )
{
printf("Running: List is empty.\n");
printf("Terminated: List is empty.\n");
}
else
{
printf("Running:\n");
while (curPtr != NULL )
{
printf("[%d] --> %s\n", curPtr->index, curPtr->pname);
curPtr = curPtr->nextPtr;
}
printf("Finished:\n");
while (curPtr != NULL )
{
printf("[%d] --> %s (pid = %d)\n", curPtr->index, curPtr->pname,
curPtr->pid);
curPtr = curPtr->nextPtr;
}
}
}
void ioredirection()
{
int input = -1, output = -1, append = -1;
int k, d, fdinput, fdoutput;
for (k = 0; argsexec[k] != NULL ; k++)
{
if (strcmp(argsexec[k], "<") == 0)
{
argsexec[k] = NULL;
input = k;
d = 1;
}
else if (strcmp(argsexec[k], ">") == 0)
{
argsexec[k] = NULL;
output = k;
d = 2;
}
else if (strcmp(argsexec[k], ">>") == 0)
{
argsexec[k] = NULL;
append = k;
d = 3;
}
if (d == 1)
{
fdinput = open(argsexec[input + 1], O_RDONLY, 0);
dup2(fdinput, STDIN_FILENO);
close(fdinput);
execvp(argsexec[0], argsexec);
}
if (d == 2)
{
int x, y;
char buffer[1024];
fdinput = open(argsexec[output - 1], O_RDONLY);
fdoutput = open(argsexec[output + 1], CREATE_FLAG, CREATE_MODE);
dup2(fdoutput, STDOUT_FILENO);
x = read(fdinput, buffer, 1024);
write(fdoutput, buffer, x);
close(fdinput);
close(fdoutput);
for (y = output; y < MAXARGNUM - 2; y++)
argsexec[y] = argsexec[y + 2];
argsexec[MAXARGNUM - 2] = NULL;
}
if (d == 3)
{
int x, y;
char buffer[1024];
fdinput = open(argsexec[output - 1], O_RDONLY);
fdoutput = open(argsexec[output + 1], CREATE_FLAGS, CREATE_MODE);
x = read(fdinput, buffer, 1024);
write(fdoutput, buffer, x);
close(fdinput);
close(fdoutput);
}
}
}
void add_path(char **dir, const char *begin, const char *end) //do the memory allocations, and add to the specified arrays.
{
if (end == begin)
{
begin = " ";
end = begin + 1;
}
size_t len = end - begin;
*dir = malloc(len + 1);
memmove(*dir, begin, len);
(*dir)[len] = '\0';
}
size_t tokenize(const char *path, char **dirs, size_t max_dirs, char delim) //tokenize the given input, with the given delimiter
{ //returns the size of the splitted parts of the string.
const char *begin = path;
const char *end;
size_t num_dirs = 0;
while (num_dirs < max_dirs && (end = strchr(begin, delim)) != 0)
{
add_path(&dirs[num_dirs++], begin, end);
begin = end + 1;
}
if (num_dirs < max_dirs && *begin != '\0')
add_path(&dirs[num_dirs++], begin, begin + strlen(begin));
return num_dirs;
}
void clearArgs()
{
int i;
for (i = 0; i < MAXARGNUM; ++i)
{
argsexec[i] = NULL;
}
}
int Ampersand()
{
int i;
for (i = 0; argsexec[i] != NULL ; i++)
{
if (strcmp(argsexec[i], "&") == 0)
{
return 1;
}
else
{
return 0;
}
}
}
void Setup()
{
while (1)
{
path = malloc((MAXCHARNUM + 1) * sizeof(char));
clearArgs();
fprintf(stderr, "333sh: ", NULL );
gets(str); //get the next commands
while (strlen(str) == 0)
{ //if the user enters empty string or space, ignore this input, read again.
fprintf(stderr, "333sh: ", NULL );
gets(str);
}
size_t commands = tokenize(str, argsexec, MAXARGNUM, ' ');
const char *path = getenv("PATH"); //get the system's path
ioredirection();
char * const arguments[] =
{ argsexec[0], argsexec[1], argsexec[2], argsexec[3], argsexec[4],
argsexec[5], argsexec[6], argsexec[7], (void*) NULL };
name = argsexec[0];
pid_t pid = fork();
wait(NULL );
if (Ampersand())
{
if (pid == 0)
{
int in = 1;
addJob(&list, pid, name, in);
}
}
if (pid == 0)
{
if (!Ampersand())
{
if (path == NULL )
{ //execl part
execl(path, argsexec[0], argsexec[1], argsexec[2], argsexec[3],
argsexec[4], argsexec[5], argsexec[6], argsexec[7], NULL );
}
else if (strcmp(argsexec[0], "dir") == 0 && argsexec[1] == NULL )
{
system("ls");
}
else if (strcmp(argsexec[0], "clr") == 0)
{
system("clear");
}
else if (strcmp(argsexec[0], "cd") == 0 && argsexec[1] == NULL )
{
system("pwd");
}
else if (strcmp(argsexec[0], "list_jobs") == 0 && argsexec[1] == NULL )
{
printJob(list);
}
else
{ //execvp part
execvp(argsexec[0], arguments);
}
}
}
}
}
int main(int argc, char const *argv[])
{
Setup();
return 0;
}
So how can i design a history part of this project ? Any idea would be appreciated.And sorry for asking that much long code.
Thanks
One way would be to create an array of 10 pointers to NULL initially. Add a routine update_history(<cmd issued>) or such that you call after every command you allow in your shell. It should:
(1) 1st call: malloc() space for the first command issued, and store the pointer to the
heap area in the array's first position
(2) Later calls: check the array for the first position with a NULL pointer, and store a pointer to the command there (using malloc() again). If you find no NULL pointer in the array (history is 10 commands long), go to (3)
(3) execute another new routine move_history(cmd issued). It moves the second array position (pointer) to the first, the 3rd to the 2nd, ..., the 10th to the 9th, and inserts a pointer to where <cmd_issued> is stored on the heap (using another malloc()) into the last array position. Don't forget to free() the heap memory that was allocated for the formerly first element that is no longer tracked.
You could then very easily print out the entire history (print through the array of pointers until you find a NULL pointer, but no more than 10 p/os; and print the command history numbers 1-10 (or 0-9) before the strings); and to print a particular command, you know in which array row the pointer to it is (if 1-based numbering, in row i-1). You can then read it and re-issue the command (don't forget to make that part of your history too).

Resources