I need help in reviewing following code.
I am trying to store anything into memory allocated ( void *) and retrive the same.
Please take a look at the code and let me know if there is anything wrong, Or if it will not work, of if there is better approach to achieve the same.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
typedef struct __c_object {
void *data;
size_t size;
} c_object;
c_object *new_c_object(void *inObject, size_t obj_size) {
c_object *tmp = (c_object*)malloc(sizeof(c_object));
tmp->size = obj_size;
tmp->data = (void*)malloc(obj_size);
memcpy ( tmp->data, inObject, obj_size);
return tmp;
}
void get_raw_c_object ( c_object *inObject, void **tmp) {
*tmp = (void*)malloc(inObject->size);
memcpy ( *tmp, inObject->data, inObject->size );
}
void delete_c_object ( c_object *inObject ) {
if (inObject ) {
free ( inObject->data );
free ( inObject);
}
inObject = ( c_object *)0;
}
int main() {
int in = 0;
c_object *co = new_c_object ( &in, sizeof(int));
void *ptrOut = (void*)0;
void *ptr = (void*)0;
get_raw_c_object( co , &ptrOut);
printf ( "Interger = [%d]\n", *(int*)ptrOut);
delete_c_object ( co );
float float_in = 10.99;
co = new_c_object ( &float_in, sizeof(float));
get_raw_c_object( co, &ptrOut);
printf ( "Float = [%f]\n", *(float*)ptrOut);
delete_c_object ( co );
int *ptr_int = ( int*) malloc ( sizeof ( int ));
in = 999;
ptr = ∈
co = new_c_object ( ptr, sizeof(int*));
get_raw_c_object( co,&ptrOut );
printf ( "Interger Pointer = [%d]\n", *(int*)ptrOut);
delete_c_object ( co );
char *inStr = "Hello Hello Hello";
char *inStrDup = _strdup (inStr);
co = new_c_object ( inStrDup, strlen(inStr) + 1);
free ( inStrDup );
get_raw_c_object( co ,&ptrOut);
printf ( "Character = [%s]\n", (char*)ptrOut);
delete_c_object ( co );
char *inStr2 = "Hello Hello Hello";
co = new_c_object ( inStr2, strlen(inStr2) + 1);
get_raw_c_object( co,&ptrOut );
printf ( "Character = [%s]\n", (char*)ptrOut);
delete_c_object ( co );
}
One Problem in the code it that get_raw_c_object( co, &ptrOut); allocates memory with malloc (returned by ptrOut) yet you never free that memory!
I don't exactly know what you are trying to achive but take a look at the following pseudo C/C++ code. Maybe it can help you:
typedef struct Variadic {
enum DataType type;
union {
char charData;
short shortData;
int intData;
unsigned int uintData;
char *charPtrData;
[...]
} data;
};
// functions for allocation and destruction
Variadic* new_variadic();
void delete_variadic(Variadic*);
// using the variadic
Variadic *a = new_variadic;
a->type = TYPE_INT;
a->data.intData = 10;
In case of a char* string delete_variadic would also delete the contained string.
You do really much copying with your objects. So I hope that all the types you want to store support being copied. One counter-example that comes to mind is a node of a doubly linked list, because there are some pointers outside that point to that exact address.
But as long as your data is not referenced from the outside, this works. You also need to make sure that your program has enough memory available, otherwise you run into undefined behavior as soon as malloc returns NULL.
In the delete_c_object function you don't need to zero out inObject. That statement has no effect at all.
The section for the integer pointer is missing one level of pointers. It looks just like the integer section.
Related
I'am working on a project for my programming class (teoretically in C++ but our professor isn't big fan of C++ solutions and C is better viewed by him). The project is to do simple queue with type given by user and the problem is with the following code:
#include <cstdlib>
#include <cstring>
#include <stdio.h>
typedef struct
{
int nKey;
int* pTab;
}Usertype;
Usertype* AllocateUsertype( );
void PrintUsertype( Usertype* pItem );
int main()
{
Usertype *pItem = AllocateUsertype();
printf( "nKey: %d, pTab: %d %d", pItem->nKey, pItem->pTab[0], pItem->pTab[1] );
pItem->nKey = 3;
PrintUsertype( pItem );
}
Usertype* AllocateUsertype( )
{
Usertype* pItem = NULL;
int* t = NULL;
t = (int*)malloc( 2*sizeof( int ) );
if( !t ) return NULL;
memset( t, 0, 2*sizeof( int ) );
Usertype Item = { 0,t };
pItem = &Item;
return pItem;
}
void PrintUsertype( Usertype* pItem )
{
printf( "nKey: %d, pTab: %d %d", pItem->nKey, pItem->pTab[0], pItem->pTab[1] );
}
When I allocate usertype it works well and the pItem is created as expected, but after I printf it it's seemes like pItem is no longer there and there's just garbage nKey number and there isn't any tab.
Is this problem because im allocating this data struct in memory wrongly and somehow t as a local variable for AllocateUsertype disapears at random moment? If yes can someone give me idea how to do it correctly?
As pointed out in the comments, the problem is that inside AllocateUsertype() you are returning a pointer to a local variable that won't exists anymore once the function returns.
The solution is to allocate a Usertype using malloc, just like you did for t, and then return its pointer.
Usertype* AllocateUsertype( )
{
Usertype* pItem = NULL;
pItem = (Usertype*)malloc(sizeof(Usertype));
if (!pItem) return NULL;
int* t = NULL;
t = (int*)malloc( 2*sizeof( int ) );
if( !t ) return NULL;
memset( t, 0, 2*sizeof( int ) );
pItem->nKey = 0;
pItem->pTab = t;
return pItem;
}
So i created a program that makes a stack and all of its operations, using a structure called stack.
Structure:
typedef struct {
int *v; /* contents of the stack */
int cap; /* capacity of v, i.e. how many elements can fit in v */
int sz; /* number of elements currently stored in v */
} stack;
The program works fine but when i use fsantize it says that there is a buffer overflow on the heap in the Push function and i dont understand why because ive reallocated the bytes that i needed and freed the ones that i didnt need.
Program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int *v; /* contents of the stack */
int cap; /* capacity of v, i.e. how many elements can fit in v */
int sz; /* number of elements currently stored in v */
} stack;
void init(stack * s)
{
s->v = (int*) calloc(4,sizeof(int));
s->cap = 4;
s->sz = -1;
}
int is_empty(stack * s)
{
if (s->sz == -1)
return 1;
else
return 0;
}
void push(stack * s, int e)
{
if (s->sz+1 <= s->cap)
{
s->sz++;
s->v[s->sz] = e;
}
else
{
int *nv;
s->cap++;
s->sz++;
nv = (int*) realloc(s->v, sizeof(int)*s->cap);
free(s->v);
s->v = nv;
s->v[s->sz] = e;
}
}
int pop(stack * s)
{
if (is_empty(s) == 0)
{
int top = s->v[s->sz];
s->sz--;
return top;
}
else
{
printf("Impossible the stack isn't empty\n");
return 0;
}
}
void destroy(stack * s)
{
//frees the stack bytes that were allocated
free(s->v);
free(s);
}
int main()
{
int i;
stack *pilha = (stack*) malloc(sizeof(stack));
init(pilha);
if (is_empty(pilha) == 1)
printf("The stack is empty\n");
pop(pilha);
for (i = 0; i<=4;i++)
push(pilha,i);
push(pilha,5);
printf("The top is:%d\n",pilha->v[pilha->sz]);
if (is_empty(pilha) == 0)
printf("The stack isn't empty\n");
destroy(pilha);
return 0;
}
This line:
if (s->sz+1 <= s->cap)
contains a logical error: if s->sz+1 == s->cap you need more space. For example, if s->cap is 4 you only have space for 4 elements (indexes from 0 to 3), but in the case of s->sz == 3 you enter the if and the result is:
s->sz++; // 4
s->v[s->sz] = e; // s->v[4] overflow!
The right way to check would be if (s->sz+1 < s->cap), or even incrementing the value first:
s->sz++;
if (s->sz < s->cap) {
// ...
This:
nv = (int*) realloc(s->v, sizeof(int)*s->cap);
free(s->v);
s->v = nv;
Is also wrong. First, you are assuming that realloc() allocates new memory and that you need to free() the old buffer: you don't, realloc() does that for you if needed. Secondly, you are assuming that realloc() does not fail (as you are doing anywhere else in your code, malloc(), calloc(), etc). Third, you are casting the return value (again as you are doing anywhere else in your code), which you shouldn't (see Do I cast the result of malloc?).
What you should do instead is:
nv = realloc(s->v, sizeof(int)*s->cap);
if (nv == NULL) {
// Handle error, abort execution.
}
s->v = nv;
The check if (nv == NULL) should be done after every single call of malloc(), realloc() or calloc().
The function push is invalid.
This condition in the if statement
if (s->sz+1 <= s->cap)
can be a reason of undefined behavior. Let's assume for simplicity that s->cap is equal to 1. So you may push only one element without resizing the dynamically allocated array. So after pushing a new value s->sz will be equal to 0. And you may not push one more a new value without resizing the array. However the condition in the if statement will evaluate to true and you will write to memory outside the allocated array.
Also this code snippet
nv = (int*) realloc(s->v, sizeof(int)*s->cap);
free(s->v);
is invalid. In the case when the call of realloc was successful the memory pointed to by s->v was freed (or rreused). So the call of free again will invoke undefined behavior. That is whether there will be an attempt to free the already reallocated memory or the new allocated memory will be freed.
The function push can be defined for example the following way
int push( stack *s, int e )
{
int success = 0;
if ( ( success = s->sz+1 < s->cap ) )
{
s->v[++s->sz] = e;
}
else
{
int *nv = realloc( s->v, sizeof( int ) * ( s->cap + 1 ) );
success = nv != NULL;
if ( success )
{
s->v = nv;
++s->cap;
s->v[++s->sz] = e;
}
}
return success;
}
But in any case it would be better to set the initial value to the data member sz to 0. In this case the data member would reflect the current size of the stack.
The return value of the function pop is ambiguous. The returned value 0 can be a valid value stored in the stack. Also the function shall shall not issue any message. It is the caller of the function that will decide whether to issue a message if any or not.
Also there is no need to allocate the object itself of the type stack dynamically. It can have the automatic storage duration and be a local variable.
And it is much better when the function that initialize the stack also has a second parameter that allows to specify the capacity of the created stack instead of using the magic number 4.
Below there is a demonstrative program that shows how the stack and its functions can be defined.
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int *v; /* contents of the stack */
size_t cap; /* capacity of v, i.e. how many elements can fit in v */
size_t sz; /* number of elements currently stored in v */
} stack;
int init( stack * s, size_t capacity )
{
s->sz = 0;
s->cap = 0;
s->v = calloc( capacity, sizeof( int ) );
int success = s->v != NULL;
if ( success )
{
s->cap = capacity;;
}
return success;
}
int is_empty( const stack *s )
{
return s->sz == 0;
}
int push( stack *s, int e )
{
int success = 0;
if ( ( success = s->sz < s->cap ) )
{
s->v[s->sz++] = e;
}
else
{
int *nv = realloc( s->v, sizeof( int ) * ( s->cap + 1 ) );
success = nv != NULL;
if ( success )
{
s->v = nv;
++s->cap;
s->v[s->sz++] = e;
}
}
return success;
}
int pop( stack *s, int *value )
{
int success = !is_empty( s );
if ( success )
{
*value = s->v[--s->sz];
}
return success;
}
void destroy( stack *s )
{
free( s->v );
s->v = NULL;
s->cap = 0;
s->sz = 0;
}
int main( void )
{
stack pilha;
init( &pilha, 4 );
if ( is_empty( &pilha ) )
{
printf( "The stack is empty\n" );
}
const int N = 5;
for ( int i = 0; i < 5; i++ )
{
push( &pilha, i );
}
push( &pilha, N );
while ( ! is_empty( &pilha ) )
{
int value;
pop( &pilha, &value );
printf( "the current top value is %d\n", value );
}
destroy( &pilha );
if ( is_empty( &pilha ) )
{
printf("The stack isn't empty\n");
}
return 0;
}
The program output is
The stack is empty
the current top value is 5
the current top value is 4
the current top value is 3
the current top value is 2
the current top value is 1
the current top value is 0
The stack isn't empty
The program crashes near assignment. How could I get it to work ? Thanks in advance. Sorry if it is repost. Could not find similar example anywhere.
#include <stdio.h>
typedef struct _kv
{
char *key;
char *value;
} _kv;
typedef struct _kvs
{
_kv *kv;
int size;
} _kvs;
main()
{
_kvs a;
a.kv[0].key = "This is key One";
a.kv[0].value = "This is value One";
a.size = 1;
printf("%s = %s\n", a.kv[0].key, a.kv[0].value);
}
You have created pointers but did not make room for the memory. You need to associate some memory with the pointers by possibly using malloc.
a.size = 1;
a.kv = malloc ( a.size * sizeof ( _kv ) );
int i;
const int string_sz = 80; // Or whatever else the string size should be
for ( i = 0; i < a.size; i++ )
{
a.kv[i].key = malloc ( string_sz );
a.kv[i].value = malloc ( string_sz );
}
strcpy ( a.kv[i].key, "This is key one" );
strcpy ( a.kv[i].value, "This is value one" );
Uninitialized pointers cannot be deferenced, you must first make sure they point at valid memory.
_kvs a;
a.kv = malloc(1 * sizeof *a.kv); /* Allocate a single _kv. */
a.kv[0].key = "key";
a.kv[0].value = "value";
a.size = 1;
Or you could use memory on the stack:
_kv my_kvs[1];
_kvs a;
a.kv = my_kvs;
a.kv[0].key = "key";
a.kv[0].value = "value";
a.size = 1;
I am having some issues with a program I am writing in C, and I have surpassed my knowledge. In summary, I need to deep copy a link list from one list to another. The lists have malloc'd data in them and I need to preserve all the data without having pointers pointing at the same information.
I have only posted the code that I think is relevant. If I am missing any important contextual information please let me know.
Here is the code:
matrix.h
typedef struct matrix {
char *name;
int R;
int C;
int dim;
void (*concat_matrices)( struct matrix *A, struct matrix *B, struct matrix *ret );
} Matrix;
void concat_matrices( Matrix *A, Matrix *B, Matrix *ret ) {
int L1 = strlen( A->name );
int L2 = strlen( B->name );
int len = L1 + L2;
char *Ap = (char*)malloc(L1*sizeof(char)); strcpy(Ap,A->name);
char *Bp = (char*)malloc(L2*sizeof(char )); strcpy(Bp,B->name);
char *c = (char*)malloc(sizeof(char)*(len + 2));
c[0] = '('; strcat(c, Ap); strcat(c, Bp); c[len+1] = ')';
ret->name = (char*)malloc(sizeof(char)*(len + 2));
strcpy(ret->name, c);
ret->R = A->R; ret->C = B->C;
ret->dim = ret->R*ret->C;
free(Ap); free(Bp); free(c);
}
matrix_list.h
typedef struct node {
Matrix *M;
struct node *next;
struct node *prev;
} Node;
typedef struct matrix_list {
Node *head;
Node *tail;
int size;
void (*append)( struct matrix_list *list, Matrix *M );
void (*print)( struct matrix_list *list );
void (*reverse_print)( struct matrix_list *list );
void (*delete)( struct matrix_list *list, const char *name );
void (*delete_tail)( struct matrix_list *list );
void (*delete_head)( struct matrix_list *list );
void (*release)( struct matrix_list *list );
void (*clone_list)( struct matrix_list *from, struct matrix_list *to );
} MatrixList;
...
void clone_list( MatrixList *from, MatrixList *to ) {
if( from->head == NULL ) {
to = NULL;
} else {
Node *tmp = from->head;
while( tmp != NULL ) {
Matrix *m_copy = (Matrix*)malloc(sizeof(Matrix*));
char *c_copy = (char*)malloc(sizeof(char*)*strlen(tmp->M->name));
strcpy(c_copy,tmp->M->name);
m_copy->name=c_copy;
m_copy->R=tmp->M->R;
m_copy->C=tmp->M->C;
m_copy->concat_matrices = concat_matrices;
to->append( to,m_copy );
tmp = tmp->next;
}
}
}
main.c
chain->print(chain);
MatrixList *chain_copy = (MatrixList*)malloc(sizeof(MatrixList));
set_list_functions( chain_copy );
chain->clone_list(chain, chain_copy);
chain_copy->print(chain_copy);
The problem arises when I try and print out the clone. Because I am malloc'ing in the clone function I understand the data goes out of scope. How can I do this copy so after the function is called clone has its own version of the data?
UPDATE:
First I would like to thank you all for taking your time to answer my question, and for teaching me more about C. I have only been coding for about 3 years. And I have a lot to learn. The updated source with 0 errors from Valgrind can be found at.
http://matthewh.me/Scripts/c++/matrix_chain/ for anyone else trying to figure out things like me. User = guest Password = guest. The clone_list function now looks like this.
void clone_list( MatrixList *from, MatrixList *to ) {
if( from->head == NULL ) {
to = NULL;
} else {
Node *tmp = from->head;
while( tmp != NULL ) {
Matrix *m_copy = (Matrix*)malloc(sizeof(Matrix));
m_copy->name = (char*)malloc(strlen(tmp->M->name) + 1);
sprintf( m_copy->name, "%s", tmp->M->name );
m_copy->R=tmp->M->R;
m_copy->C=tmp->M->C;
m_copy->concat_matrices = concat_matrices;
to->append( to,m_copy );
tmp = tmp->next;
}
}
}
If anyone else sees anything else wrong and would like to add additional pointers please feel free to do so.
You haven't allowed for the null that terminates strings, so you have classic buffer overflows.
You also do not need to copy the names three times. Your current code is:
int L1 = strlen( A->name );
int L2 = strlen( B->name );
int len = L1 + L2;
char *Ap = (char*)malloc(L1*sizeof(char)); strcpy(Ap,A->name);
char *Bp = (char*)malloc(L2*sizeof(char )); strcpy(Bp,B->name);
char *c = (char*)malloc(sizeof(char)*(len + 2));
c[0] = '('; strcat(c, Ap); strcat(c, Bp); c[len+1] = ')';
ret->name = (char*)malloc(sizeof(char)*(len + 2));
strcpy(ret->name, c);
ret->R = A->R; ret->C = B->C;
ret->dim = ret->R*ret->C;
free(Ap); free(Bp); free(c);
This should be:
int L1 = strlen(A->name);
int L2 = strlen(B->name);
ret->name = (char *)malloc(L1 + L2 + sizeof("()")); // That adds 3
sprintf(ret->name, "(%s%s)", A->name, B->name);
ret->R = A->R;
ret->C = B->C;
ret->dim = ret->R * ret->C;
This eliminates Ap, Bp and c altogether, and avoids the buffer overflow problems. I'm not sure I'd slam the two names together like you do, but that's your choice.
Apparently, this isn't sufficient of a problem...there are other issues too.
void clone_list( MatrixList *from, MatrixList *to ) {
if (from->head == NULL) {
to = NULL;
} else {
Node *tmp = from->head;
while( tmp != NULL ) {
Matrix *m_copy = (Matrix*)malloc(sizeof(Matrix*));
char *c_copy = (char*)malloc(sizeof(char*)*strlen(tmp->M->name));
strcpy(c_copy,tmp->M->name);
m_copy->name=c_copy;
m_copy->R=tmp->M->R;
m_copy->C=tmp->M->C;
m_copy->concat_matrices = concat_matrices;
to->append( to,m_copy );
tmp = tmp->next;
}
}
}
The first assignment zeroes the local pointer; it doesn't do a thing to the MatrixList passed in as the target. This should presumably be:
if (from->head == 0)
{
*to = *from;
}
This does a wholesale structure copy, but sets the head and tail to null, and the function pointers are all fine - they can be shared. Assuming that the size in from was correctly zero, it will be correct in to too. (Again, this is probably not the code you are exercising.)
The next problem is with the memory allocation:
Matrix *m_copy = (Matrix*)malloc(sizeof(Matrix*));
This allocates one pointer's worth of memory, not one Matrix's worth. Use either of these:
Matrix *m_copy = (Matrix *)malloc(sizeof(*m_copy));
Matrix *m_copy = (Matrix *)malloc(sizeof(Matrix));
That is a major source of your trouble (and one which valgrind will find easily).
When the +1 gets forgotten once, it gets forgotten many times, but this time it doesn't cause problems unless the name is the empty string because you multiply by 4 or 8 (32-bit or 64-bit) because of the sizeof(char *) instead of the intended sizeof(char).
char *c_copy = (char*)malloc(sizeof(char*)*strlen(tmp->M->name));
strcpy(c_copy,tmp->M->name);
This should probably be:
m_copy->name = (char *)malloc(strlen(tmp->M->name) + 1);
strcpy(m_copy->name, tmp->M->name);
I'd probably use a name like old instead of tmp. I am also remiss in not reminding previously that you should religiously check every return from every memory allocation. Or use a set of cover functions for the memory allocation routines which do the check for you (often called xmalloc() or emalloc(), etc.).
The code below that does not seem to copy the dim member across, which is a bug if you ever depend on it.
I'm not entirely happy that you seem to rely on the to list being appropriately initializes before calling clone_list(). In particular, the head, tail and size members are not zeroed here, and the function pointers are not set. I'd be happier to see something like:
*to = *from; // Copy function pointers
to->head = 0;
to->tail = 0;
to->size = 0;
Node *old = from->head;
for (Node *old = from->head; old != NULL; old = old->next)
{
Matrix *m_copy = clone_matrix(old->M);
to->append(to, m_copy);
}
Or even:
matrixlist_initialize(to);
Node *old = from->head;
for (Node *old = from->head; old != NULL; old = old->next)
{
Matrix *m_copy = clone_matrix(old->M);
to->append(to, m_copy);
}
The clone_matrix() function looks like:
Matrix *clone_matrix(const Matrix *old)
{
Matrix *m_copy = (Matrix*)malloc(sizeof(*m_copy));
m_copy->name = (char*)malloc(strlen(old->name)+1);
strcpy(m_copy->name, old->name);
m_copy->R = old->R;
m_copy->C = old->C;
m_copy->dim = old->dim;
m_copy->concat_matrices = concat_matrices;
return(m_copy);
}
I downloaded a version your code and it now seems to work, more or less. You should be compiling with at least -Wall as a compiler option; I refuse to compile with anything less and usually use -Wextra too. I make too many simple-to-spot mistakes not to make full use of the compiler, and while you are learning, you will too. (I've only been coding in C for just over a quarter century; the compiler still catches typos and other silly mistakes, but I seldom have big problems once the code is compiling.)
When I turned on -Wall, there was a problem with the (unused) perm() function because it doesn't return a value even though it says it will, and there was a problem because the correct definition for main() with arguments is int main(int argc, char **argv) and you were missing one of the stars. Other than that, it seems to be working OK now - you can continue with your development.
There is a function in POSIX called strdup() which duplicates a string reliably. It is useful and avoids the off-by-one mistakes.
You should review the use of headers. They are for declarations, primarily. If you explicitly use inline (your code doesn't yet), it can be appropriate to include inline functions in a header, but otherwise, function bodies should not be in headers. They should be in source files (.c suffix). Each header should contain the minimum necessary information for the code that uses the functionality provided by the source to use. It should not include extraneous headers, but it should include all necessary headers. In matrix.h, you include <stdio.h> which is unnecessary. And if you removed the code, neither <string.h> nor <stdlib.h> would be needed either.
int L1 = strlen( A->name );
int L2 = strlen( B->name );
int len = L1 + L2;
char *Ap = (char*)malloc(L1*sizeof(char)); strcpy(Ap,A->name);
char *Bp = (char*)malloc(L2*sizeof(char )); strcpy(Bp,B->name);
I'm willing to bet that your strcpy(3) calls here have written outside the bounds of the memory you've allocated: strlen(3) does NOT account for the '\0' terminator at the end of C strings, so your *Ap and *Bp are allocated one-byte-too-short.
Because this is so common it is an easy pattern to find bugs:
int len = strlen(s);
char *new = malloc(len); /* FAIL */
If I don't see a + 1 in the malloc(3) call, it's almost certainly a bug. :) I prefer to see:
int len = strlen(s);
char *new = malloc(len + 1);
rather than:
int len = strlen(s) + 1;
char *new = malloc(len);
If you follow the former, I think it is far easier to spot the wrong cases when you forget the + 1. I think the latter one is too easy to overlook the wrong ones amidst a sea of correct ones.
Similarly, your c and ret->name have been allocated too short.
But, I think there is a far easier answer:
void concat_matrices( Matrix *A, Matrix *B, Matrix *ret ) {
int len = strlen(A->name) + strlen(B->name) + 2 + 1; /* parens + NUL */
ret->name = malloc(len);
sprintf(ret->name, "(%s%s)", A->name, B->name);
ret->R = A->R; ret->C = B->C;
ret->dim = ret->R*ret->C;
}
Use sprintf(3) to build the string in one fell swoop. You only need to allocate one string, and that's the one you intend to keep, which will reduce memory fragmentation due to frequent allocate / deallocate cycles. But the most important reason for the re-write is I think this new version is easier to read. Note I broke my rule about the + 1 here -- clarity is improved by adding together all the memory required in one line.
Update
Your clone_list() function suffers from the same problem:
Matrix *m_copy = (Matrix*)malloc(sizeof(Matrix*));
char *c_copy = (char*)malloc(sizeof(char*)*strlen(tmp->M->name));
strcpy(c_copy,tmp->M->name);
Your m_copy looks fine, because it is a binary object and the size is known exactly. But c_copy is allocated one byte too short -- it is not long enough to contain the '\0' byte that is copied into place with the strcpy(3) call immediately following. This routine too is scribbling over unallocated memory.
I have defined struct like
typedef struct {
char *oidkey;
int showperf;
char oidrealvalue[BUFSIZE];
char *oidlimits;
} struct_oidpairs;
and I have array of struct
struct_oidpairs b[] ={{.....},....}
and I want to copy it to new struct array a[]
please help
Something like this:
memcpy(dest, src, sizeof(struct) * sizeof(src));
Your struct contains pointers as data members, this means you will have to roll out your own copy function that will do something sensible with the pointers. memcpy only works is all the data related to the struct is stored in the struct.
For real copy of the contents, follow Sjoerd's answer and then:
for (i = 0; i < sizeof(src); i++)
{
if (src[i].oidkey != NULL)
{
dest[i].oidkey = malloc(strlen(src[i].oidkey) + 1);
strcpy(dest[i].oidkey, src[i].oidkey);
}
if (src[i].oidlimits != NULL)
{
dest[i].oidlimits = malloc(strlen(src[i].oidlimits) + 1);
strcpy(dest[i].oidlimits, src[i].oidlimits);
}
}
You may consider memcpy if you are interested in speed.
Update:
Following harper's code, I
updated the code to check NULL
pointers
This is a quoted note from
gordongekko:
This solution will crash if
oidkey or oidlimits are != NULL and not
'\0'-terminated means not initialized
Makes NOT a deep copy:
struct_oidpairs b[] = {...};
size_t len = sizeof b/sizeof*b;
struct_oidpairs *a = malloc(sizeof b);
if( !a ) /* ERROR handling */
memcpy( a, b, sizeof b );
...
free( a );
or
while( len-- )
a[len] = b[len];
...
free( a );
maybe using :
for(int i=0; i<b.size() ;i++)
//I am not sure if this is the correct name for the size function
{
a[i]=b[i];
}