below is the function fast_integer_output that converts input_integer from base 2 into output_base.
my_str* fast_integer_output(bigint* input_integer, int output_base)
{
bigint** integer_to_binary_array = create_integer_to_binary_array();
bigint* base = integer_to_binary_array[output_base];
my_str* result = 0;
if(less_than(input_integer, base))
{
char* p_char = (char*) get_memory(sizeof(char));
p_char[0] = int_to_char(*(input_integer->number));
result = create_string(p_char, 1);
}
else
{
long k = find_k(input_integer, base);
bigint* base_to_k = power(base, k);
bigint* quotient;
bigint* remainder;
divide(input_integer, base_to_k, "ient, &remainder);
delete_bigint(&base_to_k);
my_str* low = fast_integer_output(remainder, output_base);
delete_bigint(&remainder);
my_str* high = fast_integer_output(quotient, output_base);
delete_bigint("ient);
result = concatenate(low, k - low->length, high);
delete_string(&low);
delete_string(&high);
}
release_integer_to_binary_array(integer_to_binary_array);
return result;
}
Here are bigint and my_str structs and create_string function (bitarray is just a pointer to long)
my_str* create_string(char* c_str, long length)
{
my_str* str = (my_str*) get_memory(sizeof(my_str));
str->c_str = c_str;
str->length = length;
}
typedef struct
{
char* c_str;
long length; // logical
} my_str;
typedef struct
{
bitarray* number;
long length; // logical
long size; // physical
} bigint;
And this functions take care of memory management. Right now they are just wrapping functions to free and malloc but I would like to implement some kind of memory pool if it will be slow in operation.
void init_memory(void* memory, size_t size)
{
unsigned char* tmp = (unsigned char*) memory;
unsigned char c = 0;
while (size > 0)
{
*tmp = c;
tmp++;
size--;
}
}
void* get_memory(size_t size)
{
void* memory = malloc(size);
init_memory(memory, size);
return memory;
}
void release_memory(void** memory)
{
free(*memory);
*memory = 0;
}
Problem is that everything runs fine on debug configuration, but on release configuration the function fast_integer_output fails on the line :
result = concatenate(low, k - low->length, high);
The problem is that
my_str* low = fast_integer_output(remainder, output_base);
which returns from this piece of code
if(less_than(input_integer, base))
{
char* p_char = (char*) get_memory(sizeof(char));
p_char[0] = int_to_char(*(input_integer->number));
result = create_string(p_char, 1);
}
returns trash and thus it fails on segmentation fault.
I had the same problem with this code:
QString buffer; // function parameter in real code
instance_data_t data = {(unsigned char*) buffer.toStdString().c_str(), 0, 0, 0, 0, 0, 0, {0, 0}, {0, 0}, cur_state};
but I managed to get it working by changing it into following:
unsigned char c_buffer[1024];
memset(c_buffer, '\0', sizeof(c_buffer));
strcpy((char *) c_buffer, buffer.toStdString().c_str());
instance_data_t data = {c_buffer, 0, 0, 0, 0, 0, 0, {0, 0}, {0, 0}, cur_state};
Important note is that I cannot use any other functions than write, read, malloc and free (so no strcpy, above code is from test which I will not deliver)
This is not a homework, it is an assignment for a job (I would like to get).
I've searched and read about 15-20 questions, so I will not list them all, but the problem is that mostly, if the question is not very specific, the segmentation fault is not because of string manipulation and if it is, then it is mostly because of index out of bounds.
Your allocated string is not null ('\0') terminated.
I would do it this way :
char* p_char = (char*) get_memory(sizeof(char) * 2);
p_char[0] = int_to_char(*(input_integer->number));
p_char[1] = 0;
result = create_string(p_char, 1);
As EOF pointed out (see comments),
The create_string function as no return statement.
Thus, garbage is indeed returned.
my_str* create_string(char* c_str, long length)
{
my_str* str = (my_str*) get_memory(sizeof(my_str));
str->c_str = c_str;
str->length = length;
return str;
}
Related
I am currently working on a text editing program in C, which uses Linked Lists for rows of text. I have so far written functions for resizing the list etc., but I have now attempted to write the insert_char(Row* row, int idx, char c) however whenever I try resizing it, the resulting char* array is NULL. I am confident it's not a memory leak, as I have checked and I am free()ing all of my malloc()'d memory, so I really don't know where the problem is.
I have also tried some printf("%c", c) debugging to view the character, however the character itself is also NULL. Can anyone help me with this?
Here is the struct for a Row:
typedef struct {
char* data; // pointer to Malloc()'d char array.
int datalen;
} Row;
Here are the functions for resizing the row and allocating the Row pointer.
Row* alloc_row(char* data)
{
Row* row = (Row*) malloc(sizeof(Row));
char* data2 = (char*) malloc((sizeof(char) * strlen(data))+1);
strcpy(data2, data);
row->data = data2;
row->datalen = strlen(data);
return row;
}
// Row resize
Row* resize_row(Row* oldrow, char* data)
{
Row* new_row = (Row*) malloc(sizeof(Row));
new_row->data = data;
new_row->datalen = strlen(data);
// free() the old row
free(oldrow->data);
free(oldrow);
return new_row;
}
And here is the function I am having trouble with - it should take a Row*, create a buffer, strcpy() the Row->data up to idx, insert the char c and then copy the rest of the string afterwards, such that if I called alloc_row(Row* {.data = "Hello" .strlen=5}, 2, 'A') I would receive HeAllo (counting from zero). However, the string is NULL:
Row* insert_char(Row* row, int idx, char c)
{
char* new_row = (char*)malloc(sizeof(char) * (strlen(row->data) + 2)); // 1 char for null, char for the appended data
if (idx < strlen(row->data)) {
for (int i = 0; i < strlen(row->data)+1; i++) {
if (i < idx) new_row[i] = row->data[i];
if (i == idx) new_row[idx] = c;
if (i > idx) new_row[i] = row->data[i-1];
}
} else {
row->data[strlen(row->data)] = '\0';
strncpy(new_row, row->data, strlen(row->data));
new_row[strlen(row->data)-1] = c;
}
Row* nr = resize_row(row, new_row);
return nr;
}
Is there something wrong with my approach, and is there a cleaner and faster way of doing this?
At least these problems:
Not a string
new_row[] is not a string as it lacks a null character. Later code relies on that.
Result: undefined behavior (UB).
char* new_row = (char*)malloc(sizeof(char) * (strlen(row->data) + 2));
if (idx < strlen(row->data)) {
...
} else {
row->data[strlen(row->data)] = '\0';
strncpy(new_row, row->data, strlen(row->data));
// At this point `new_row[]` lacks a '\0'
new_row[strlen(row->data)-1] = c;
}
It is unclear exactly what OP's wants in the else block, but I think it may be:
} else {
size_t len = strlen(row->data);
strcpy(new_row, row->data);
new_row[len++] = c;
new_row[len] = '\0';
}
Minor: conceptually wrong size
The below works OK because (sizeof(char) is 1.
char* data2 = (char*) malloc((sizeof(char) * strlen(data))+1);
But should be:
char* data2 = (char*) malloc(sizeof(char) * (strlen(data) + 1));
Even better, drop the unneeded cast and size to the referenced object, not the type.
char* data2 = malloc(sizeof *data2 * (strlen(data) + 1u));
// or
char* data2 = malloc(sizeof data2[0] * (strlen(data) + 1u));
Untested alternate code
typedef struct {
char *data; // pointer to Malloc()'d char array.
//int datalen;
size_t datalen;
} Row;
// Row* insert_char(Row *row, int idx, char c) {
Row* insert_char(Row *row, size_t idx, char c) {
assert(c != 0); // Unclear what OP wants in this case
//char *new_row = (char*) malloc(sizeof(char) * (strlen(row->data) + 2));
// Why use strlen(row->data) when the length is in row->datalen ?
// Since row->data was getting free'd later in OP's code,
// let us just re-allocate instead and re-use the old row node.
char *new_row = realloc(row->data, row->datalen + 2);
assert(new_row); // TBD code to handle out-of-memory
// When idx large, simply append
if (idx > row->datalen) {
idx = row->datalen;
}
// Shift the right side over 1
memmove(new_row + idx + 1, new_row + idx, row->datalen - idx + 1); // Moves \0 too
new_row[idx] = c;
row->data = new_row;
row->datalen++;
return row;
}
I tried the following code and it works (I modified certain things to print it directly and corrected some of your suggestions on how to call the function):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char* data; // pointer to Malloc()'d char array.
int datalen;
} Row;
char* insert_char(Row* row, int idx, char c)
{
char* new_row = (char*)malloc(sizeof(char) * (strlen(row->data) + 2)); // 1 char for null, char for the appended data
if (idx < strlen(row->data)) {
for (int i = 0; i < strlen(row->data)+1; i++) {
if (i < idx) new_row[i] = row->data[i];
if (i == idx) new_row[idx] = c;
if (i > idx) new_row[i] = row->data[i-1];
}
} else {
row->data[strlen(row->data)] = '\0';
strncpy(new_row, row->data, strlen(row->data));
new_row[strlen(row->data)-1] = c;
}
return new_row;
}
int main()
{
printf("%s\n", insert_char(&(Row) {.data = "Hello", .datalen=5}, 2, 'A'));
return 0;
}
However, I think that your problem is in the for where you need +2 instead of +1 in the ending condition (since you are copying the entire array and malloc doesn't necessarly set the last char as '\0' [although calloc could do that]).
Using some of your great ideas, I have come up with the following sample which uses calloc() to initialise a section of memory to 0. I believe my issue was in fact a missing NULL byte, and I have also cleaned things significantly. Here is my improved snippet:
Row* insert_char(Row* row, int idx, char* str)
{
char* new_row = calloc(row->datalen + strlen(str) + 1, sizeof(char));
strncpy(new_row, row->data, idx);
strcat(new_row, str);
strcat(new_row, row->data + idx);
return resize_row(row, new_row);
}
NOTE: I have modified the input from a char to a char* because I plan to be inserting strings in the future, and not just single characters.
The same resize_row() method is used as in the original:
Row* resize_row(Row* oldrow, char* data)
{
Row* new_row = (Row*) malloc(sizeof(Row));
new_row->data = data;
new_row->datalen = strlen(data);
// free() the old row
free(oldrow->data);
free(oldrow);
return new_row;
}
I have an issue with memcpy and valgrind, telling me about an Invalid write of size 8.
I got to the point of figuring out where the faulty code is, but I have no clue as to why it is faulty...
I'm aware that there are other questions regarding that, but they don't help me really.
The following is an excerpt of the most important bits of my approach on a somewhat "universal" stack, when my regular value would be of type uintptr_t.
Here are two defines that I used below:
// default stack batch size
#define STACK_BATCH_DEFAULT 8
// size of one value in the stack
#define STACK_SIZEOF_ONE sizeof(uintptr_t)
The structure of the stack is as follows:
typedef struct Stack
{
size_t count; // count of values in the stack
size_t size; // size of one value in bytes
size_t alloced; // allocated count
uintptr_t *value; // the values
int batch; // memory gets allocated in those batches
}
Stack;
I have an initialization function for the stack:
bool stack_init(Stack *stack, size_t size, int batch)
{
if(!stack) return false;
stack->batch = batch ? batch : STACK_BATCH_DEFAULT;
stack->size = size;
stack->count = 0;
stack->value = 0;
stack->alloced = 0;
return true;
}
Then the stack_push function, where valgrind throws the error Invalid write of size 8:
bool stack_push(Stack *stack, uintptr_t *value)
{
if(!stack || !value) return false;
// calculate required amount of elements
size_t required = stack->batch * (stack->count / stack->batch + 1);
// allocate more memory if we need to
if(required > stack->alloced)
{
uintptr_t *tmp = realloc(stack->value, required * stack->size);
if(!tmp) return false;
stack->value = tmp;
stack->alloced = required;
}
// set the value
if(stack->size > STACK_SIZEOF_ONE)
{
memcpy(stack->value + stack->size * stack->count, value, stack->size); // <--- valgrind throws the error here
}
else
{
stack->value[stack->count] = *value;
}
// increment count
stack->count++;
return true;
}
Then in my program I'm calling the functions as follows:
Stack stack = {0};
stack_init(&stack, sizeof(SomeStruct), 0);
/* ... */
SomeStruct push = { // this is a struct that is larger than STACK_SIZEOF_ONE
.int_a = 0,
.int_b = 0,
.int_c = 0,
.id = 0,
.pt = pointer_to_struct, // it is a pointer to some other struct that was allocated beforehand
};
stack_push(&stack, (uintptr_t *)&push);
And with universal I meant that I can also have a regular stack:
Stack stack = {0};
stack_init(&stack, sizeof(uintptr_t), 0);
/* ... */
uintptr_t a = 100;
stack_push(&stack, &a);
Also, I'm open to hear general tips and advices if there are any things that should/could be improved :)
Edit: Below is a runnable code.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
// default stack batch size
#define STACK_BATCH_DEFAULT 8
// size of one value in the stack
#define STACK_SIZEOF_ONE sizeof(uintptr_t)
#define TESTCOUNT 10
#define MAX_BUF 16
typedef struct Stack
{
size_t count; // count of values in the stack
size_t size; // size of one value in bytes
size_t alloced; // allocated count
uintptr_t *value; // the values
int batch; // memory gets allocated in those batches
}
Stack;
typedef struct SomeStruct
{
size_t a;
size_t b;
size_t c;
size_t id;
char *str;
}
SomeStruct;
bool stack_init(Stack *stack, size_t size, int batch)
{
if(!stack) return false;
stack->batch = batch ? batch : STACK_BATCH_DEFAULT;
stack->size = size;
stack->count = 0;
stack->value = 0;
stack->alloced = 0;
return true;
}
bool stack_push(Stack *stack, uintptr_t *value)
{
if(!stack || !value) return false;
// calculate required amount of elements
size_t required = stack->batch * (stack->count / stack->batch + 1);
// allocate more memory if we need to
if(required > stack->alloced)
{
uintptr_t *tmp = realloc(stack->value, required * stack->size);
if(!tmp) return false;
stack->value = tmp;
stack->alloced = required;
}
// set the value
if(stack->size > STACK_SIZEOF_ONE)
{
memcpy(stack->value + stack->size * stack->count, value, stack->size); // <--- valgrind throws the error here
}
else
{
stack->value[stack->count] = *value;
}
// increment count
stack->count++;
return true;
}
bool stack_pop(Stack *stack, uintptr_t *value)
{
if(!stack) return false;
if(!stack->count) return false;
// decrement count of elements
stack->count--;
// return the value if we have an address
if(value)
{
if(stack->size > STACK_SIZEOF_ONE)
{
memcpy(value, stack->value + stack->size * stack->count, stack->size);
}
else
{
*value = stack->value[stack->count];
}
}
int required = stack->batch * (stack->count / stack->batch + 1);
if(required < stack->alloced)
{
uintptr_t *tmp = realloc(stack->value, required * stack->size);
if(!tmp) return false;
stack->value = tmp;
stack->alloced = required;
}
if(!stack->value) return false;
return true;
}
int main(void)
{
// initialize variables
bool valid = false;
Stack default_stack = {0};
Stack some_stack = {0};
// initialize stacks
stack_init(&default_stack, sizeof(uintptr_t), 0);
stack_init(&some_stack, sizeof(SomeStruct), 0);
// test default case - push
printf("Testing the default case, pushing...\n");
for(int i = 0; i < TESTCOUNT; i++)
{
uintptr_t push = i;
valid = stack_push(&default_stack, &push);
if(!valid) return -1;
}
// ...now pop
printf("Testing the default case, popping...\n");
do
{
uintptr_t pop = 0;
valid = stack_pop(&default_stack, &pop);
if(valid) printf("%llu,", pop);
}
while(valid);
printf("\n");
// test some case - push
printf("Testing some case, pushing...\n");
for(int i = 0; i < TESTCOUNT; i++)
{
// generate the push struct
SomeStruct push = {
.a = i * 10,
.b = i * 100,
.c = i * 1000,
.id = i,
.str = 0,
};
// allocate a string
push.str = malloc(MAX_BUF + 1);
snprintf(push.str, MAX_BUF, "%d", i);
// push
valid = stack_push(&some_stack, (uintptr_t *)&push);
if(!valid) return -1;
}
// ...now pop
printf("Testing some case, popping...\n");
do
{
SomeStruct pop = {0};
valid = stack_pop(&some_stack, (uintptr_t *)&pop);
if(valid)
{
printf("a=%d,b=%d,c=%d,id=%d,str=%s\n", pop.a, pop.b, pop.c, pop.id, pop.str);
free(pop.str);
}
}
while(valid);
printf("\n");
/* leave out free functions for this example.... */
return 0;
}
After hours I figured it out :D The mistake happened because I very rarely do pointer arithmetic... In short, I was assuming that it would always calculate with a byte.
Let's take a look at the lines containing:
memcpy(stack->value + stack->size * stack->count, value, stack->size);
...and break it down, so it is more readable. And also, I'll even add a handy dandy comment in it:
size_t offset = stack->size * stack->count; // offset in bytes
void *dest = stack->value + offset;
void *src = value;
memcpy(dest, src, stack->size);
Now the pro C-programmer should instantly spot the problem. It is with the calculation of stack->value + offset, where it should add offset in bytes but it is not, because the stack->value is of type uintptr_t * and not of type uint8_t *.
So to fix it, I replaced it with this line:
void *dest = (uint8_t *)stack->value + offset;
And the code works.
pointers always get me in C programing.
I am having trouble, I want to pass a pointer to an array of structs into a function so it can modify the structs and then pass the members of the array can be used in other functions later. The problem is when I think I index the array and point it to the modified struct then I try to look at the members later they aren't the modified values. Here is some of my code
typedef struct
{
int rows;
int columns;
int *data;
} Mat;
int main(void)
{
Mat result, decoded_result;
int result_data[8] =
{ 0, 0, 0, 0, 0, 0, 0, 0 };
int decoded_data[4] =
{ 0, 0, 0, 0 };
result.columns = 1;
result.rows = 8;
result.data = &result_data[0];
decoded_result.columns = 1;
decoded_result.rows = 4;
decoded_result.data = &decoded_data[0];
Mat m1, m2, m3, m4, m5;
m1.rows = m2.rows = m3.rows = m4.rows = m5.rows = 4;
m1.columns = m2.columns = m3.columns = m4.columns = m5.columns = 1;
int md1[4], md2[4], md3[4], md4[4], md5[4];
m1.data = &md1[0], m2.data = &md2[0], m3.data = &md3[0], m4.data = &md4[0], m5.data =
&md5[0];
Mat mat_array[10] =
{ m1, m2, m3, m4, m5 };
decode_data(&result, &decoded_result, mat_array);
return 0;
}
int decode_data(Mat *result, Mat *decoded_result, Mat *mat_array)
{
int ii;
int size_of_EEPROM = 5;
//steps to decode data
for (ii = 0; ii < size_of_EEPROM; ii++)
{
decode(result, decoded_result); //decodes hamming 8,4, works
mat_array[ii] = *decoded_result; ///This is where the problem is
}
return 0;
}
Thanks in advance for the help with pointers :)
As Mat carries a pointer, simply assigning Mat a to Mat b won't work. At least not for the data referenced by Mat's member data.
What's needed to be done here is also called a Deep Copy. Deep coping would also create a copy of what is referenced by data.
Below is an example of how this could be done for Mat.
Note: As negative rows and columns are of no use you'd better declare Mat like this:
typedef struct
{
size_t rows;
size_t columns;
int * data;
} Mat;
(As size_t is defined to be unsigned this kind of declaration makes it unnecessary to test for negative values carried by the members rows and columns before allocating the new data when deep-coping as shown below)
#include <stdlib.h> /* for malloc(), size_t */
#include <string.h> /* for memcpy() */
#include <errno.h> /* for errno, ENOMEM, EINVAL */
...
/* Deep-copies src to dst. */
/* Returns 0 on success or -1 on error. Sets errno in the latter case. */
int mat_copy(Mat * dst, const Mat * src)
{
if ((!dst) || (!src))
{
errno = EINVAL;
return -1;
}
dst->rows = src->row;
dst->columns = src->columns
dst->data = NULL;
if (src->data)
{
size_t size = dst->rows * dst->columns * sizeof (*(dst->data));
dst->data = malloc(size);
if (!dst->data)
{
errno = ENOMEM;
return -1;
}
memcpy(dst->data, src->data, size);
}
return 0;
}
There is rule of three in C++ when using pointers. It says that if you need one of following then you need other two always. These three are Destructor/Copy Constructor/Assign Operator.
So what happen's in your scenario. When you write mat_array[ii] = *decoded_result it actually makes:
mat_array[ii].rows = decoded_result.rows;
mat_array[ii].columns = decoded_result.columns;
mat_array[ii].data = decoded_result.data // here just assign pointers, not the entire data.
In this case you have to make assignment operator to make actual copy of data.
I am working on a kernel module and I need to compare two buffers to find out if they are equivalent. I am using the memcmp function defined in the Linux kernel to do so. My first buffer is like this:
cache_buffer = (unsigned char *)vmalloc(4097);
cache_buffer[4096] = '/0';
The second buffer is from a page using the page_address() function.
page = bio_page(bio);
kmap(page);
write_buffer = (char *)page_address(page);
kunmap(page);
I have printed the contents of both buffers before hand and not only to they print correctly, but they also have the same content. So next, I do this:
result = memcmp(write_buffer, cache_buffer, 2048); // only comparing up to 2048 positions
This causes the kernel to freeze up and I cannot figure out why. I checked the implementation of memcmp and saw nothing that would cause the freeze. Can anyone suggest a cause?
Here is the memcmp implementation:
int memcmp(const void *cs, const void *ct, size_t count)
{
const unsigned char *su1, *su2;
int res = 0;
for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
if ((res = *su1 - *su2) != 0)
break;
return res;
}
EDIT: The function causing the freeze is memcmp. When I commented it out, everything worked. Also, when I did I memcmp as follows
memcmp(write_buffer, write_buffer, 2048); //comparing two write_buffers
Everything worked as well. Only when I throw the cache_buffer into the mix is when I get the error. Also, above is a simplification of my actual code. Here is the entire function:
static int compare_data(sector_t location, struct bio * bio, struct cache_c * dmc)
{
struct dm_io_region where;
unsigned long bits;
int segno;
struct bio_vec * bvec;
struct page * page;
unsigned char * cache_data;
char * temp_data;
char * write_data;
int result, length, i;
cache_data = (unsigned char *)vmalloc((dmc->block_size * 512) + 1);
where.bdev = dmc->cache_dev->bdev;
where.count = dmc->block_size;
where.sector = location << dmc->block_shift;
printk(KERN_DEBUG "place: %llu\n", where.sector);
dm_io_sync_vm(1, &where, READ, cache_data, &bits, dmc);
length = 0;
bio_for_each_segment(bvec, bio, segno)
{
if(segno == 0)
{
page = bio_page(bio);
kmap(page);
write_data = (char *)page_address(page);
//kunmap(page);
length += bvec->bv_len;
}
else
{
page = bio_page(bio);
kmap(page);
temp_data = strcat(write_data, (char *)page_address(page));
//kunmap(page);
write_data = temp_data;
length += bvec->bv_len;
}
}
printk(KERN_INFO "length: %u\n", length);
cache_data[dmc->block_size * 512] = '\0';
for(i = 0; i < 2048; i++)
{
printk("%c", write_data[i]);
}
printk("\n");
for(i = 0; i < 2048; i++)
{
printk("%c", cache_data[i]);
}
printk("\n");
result = memcmp(write_data, cache_data, length);
return result;
}
EDIT #2: Sorry guys. The problem was not memcmp. It was the result of memcmp. When ever it returned a positive or negative number, the function that called my function would play with some pointers, one of which was uninitialized. I don't know why I didn't realize it before. Thanks for trying to help though!
I'm no kernel expert, but I would assume you need to keep this memory mapped while doing the comparison? In other words, don't call kunmap until after the memcmp is complete. I would presume that calling it before will result in write_buffer pointing to a page which is no longer mapped.
Taking your code in the other question, here is a rough attempt at incremental. Still needs some cleanup, I'm sure:
static int compare_data(sector_t location, struct bio * bio, struct cache_c * dmc)
{
struct dm_io_region where;
unsigned long bits;
int segno;
struct bio_vec * bvec;
struct page * page;
unsigned char * cache_data;
char * temp_data;
char * write_data;
int length, i;
int result = 0;
size_t position = 0;
size_t max_size = (dmc->block_size * 512) + 1;
cache_data = (unsigned char *)vmalloc(max_size);
where.bdev = dmc->cache_dev->bdev;
where.count = dmc->block_size;
where.sector = location << dmc->block_shift;
printk(KERN_DEBUG "place: %llu\n", where.sector);
dm_io_sync_vm(1, &where, READ, cache_data, &bits, dmc);
bio_for_each_segment(bvec, bio, segno)
{
// Map the page into memory
page = bio_page(bio);
write_data = (char *)kmap(page);
length = bvec->bv_len;
// Make sure we don't go past the end
if(position >= max_size)
break;
if(position + length > max_size)
length = max_size - position;
// Compare the data
result = memcmp(write_data, cache_data + position, length);
position += length;
kunmap(page);
// If the memory is not equal, bail out now and return the result
if(result != 0)
break;
}
cache_data[dmc->block_size * 512] = '\0';
return result;
}
I'm looking for an efficient method for appending multiple strings.
The way it should work is C++ std::string::append or JAVA StringBuffer.append.
I wrote a function which actually reallocs previous source pointer and does strcat.
I believe this is not an efficient method as compiler may implement this free and malloc.
Other way I could think of (like std::vector) is allocate memory in bulk (1KB for eg) and do strcpy. In that case every append call will check if the total required allocation is more than (1200 bytes) the amount allocated in bulk, realloc to 2KB. But in that case there will be some memory wasted.
I'm looking for a balance between the above but the preference is performance.
What other approaches are possible. Please suggest.
I would add each string to a list, and add the length of each new string to a running total. Then, when you're done, allocate space for that total, walk the list and strcpy each string to the newly allocated space.
The classical approach is to double the buffer every time it is too small.
Start out with a "reasonable" buffer, so you don't need to do realloc()s for sizes 1, 2, 4, 8, 16 which are going to be hit by a large number of your strings.
Starting out at 1024 bytes means you will have one realloc() if you hit 2048, a second if you hit 4096, and so on. If rampant memory consumption scares you, cap the growth rate once it hits something suitably big, like 65536 bytes or whatever, it depends on your data and memory tolerance.
Also make sure you buffer the current length, so you can do strcpy() without having to walk the string to find the length, first.
Sample function to concatenate strings
void
addToBuffer(char **content, char *buf) {
int textlen, oldtextlen;
textlen = strlen(buf);
if (*content == NULL)
oldtextlen = 0;
else
oldtextlen = strlen(*content);
*content = (char *) realloc( (void *) *content, (sizeof(char)) * (oldtextlen+textlen+1));
if ( oldtextlen != 0 ) {
strncpy(*content + oldtextlen, buf, textlen + 1);
} else {
strncpy(*content, buf, textlen + 1);
}
}
int main(void) {
char *content = NULL;
addToBuffer(&content, "test");
addToBuffer(&content, "test1");
}
I would do something like this:
typedef struct Stringbuffer {
int capacity; /* Maximum capacity. */
int length; /* Current length (excluding null terminator). */
char* characters; /* Pointer to characters. */
} Stringbuffer;
BOOL StringBuffer_init(Stringbuffer* buffer) {
buffer->capacity = 0;
buffer->length = 0;
buffer->characters = NULL;
}
void StringBuffer_del(Stringbuffer* buffer) {
if (!buffer)
return;
free(buffer->characters);
buffer->capacity = 0;
buffer->length = 0;
buffer->characters = NULL;
}
BOOL StringBuffer_add(Stringbuffer* buffer, char* string) {
int len;
int new_length;
if (!buffer)
return FALSE;
len = string ? strlen(string) : 0;
if (len == 0)
return TRUE;
new_length = buffer->length + len;
if (new_length >= new_capacity) {
int new_capacity;
new_capacity = buffer->capacity;
if (new_capacity == 0)
new_capacity = 16;
while (new_length >= new_capacity)
new_capacity *= 2;
new_characters = (char*)realloc(buffer->characters, new_capacity);
if (!new_characters)
return FALSE;
buffer->capacity = new_capacity;
buffer->characters = new_characters;
}
memmove(buffer->characters + buffer->length, string, len);
buffer->length = new_length;
buffer->characters[buffer->length] = '\0';
return TRUE;
}