My arraylist implementation stop working after appending 32754 elements. I think it is very weird that this problem only occurs after appending so many elements and 32000 is still not too high to reach I know I am not checking for NULL pointer and that my test program is a infinite loop. I am using a old version to reduce the code complexity.
output:
32752
32753
32754
zsh: segmentation fault ./acl
array.c:
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
union arraylist_meta {
double dummy_double;
long double dummy_long_double;
long long dummy_long_long;
void *dummy_ptr;
void (*dummy_func_ptr)(void);
struct {
size_t len;
size_t cap;
size_t sizeof_one_element;
};
};
void* acl_arraylist_create(size_t array_size, size_t sizeof_one_element) {
union arraylist_meta *arraylist_new = malloc(array_size * sizeof_one_element + sizeof*arraylist_new);
arraylist_new->len = array_size;
arraylist_new->cap = array_size;
arraylist_new->sizeof_one_element = sizeof_one_element;
return arraylist_new+1;
}
void* acl_arraylist_append(void *arraylist_void, void *element) {
union arraylist_meta *arraylist = arraylist_void;
--arraylist;
if(arraylist->len == arraylist->cap) {
arraylist->cap = arraylist->len + 10;
arraylist = realloc(arraylist, arraylist->cap * arraylist->sizeof_one_element + sizeof *arraylist);
}
memcpy((char*)(arraylist + 1) + arraylist->sizeof_one_element * arraylist->len, element, arraylist->sizeof_one_element);
++arraylist->len;
return arraylist+1;
}
array.h:
#ifndef array_h
#define array_h
#include <stddef.h>
void* acl_arraylist_create(size_t array_size, size_t sizeof_one_element);
void* acl_arraylist_append(void *arraylist_void, void *element_void);
#endif
a simple test programm:
#include <acl/array.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
int *num = acl_arraylist_create(0, sizeof *num);
for(int i = 0;;++i) {
num = acl_arraylist_append(num, &i);
printf("%d\n", i);
}
}
Edit:
I changed the of the executable a while ago. By reverting a few commits back my build script was using the old name again, but executed the executable with name. This means that the problem I describe above does not with code above. It only occurs when using the code below:
array.c:
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <acl/array.h>
size_t acl_arraylist_len(void *arraylist);
void acl_arraylist_free(void *arraylist);
static inline void* acl_arraylist_resize(union acl_arraylist_meta *arraylist, int64_t relativLen) {
size_t cap = arraylist->cap + relativLen;
arraylist = realloc(arraylist, cap * arraylist->sizeof_one_element + sizeof *arraylist);
if(arraylist != NULL) {
arraylist->cap = cap;
}
return arraylist;
}
void* acl_arraylist_create(size_t array_size, size_t sizeof_one_element) {
union acl_arraylist_meta *arraylist_new = malloc(array_size * sizeof_one_element + sizeof*arraylist_new);
if(arraylist_new == NULL) return NULL;
arraylist_new->len = array_size;
arraylist_new->cap = array_size;
arraylist_new->sizeof_one_element = sizeof_one_element;
return arraylist_new+1;
}
void* acl_arraylist_append(void *arraylist_void, void *element) {
void *element_append;
union acl_arraylist_meta *arraylist = acl_arraylist_append_ptr(arraylist_void, &element_append);
if(arraylist == NULL) return NULL;
--arraylist;
memcpy(element_append, element, arraylist->sizeof_one_element);
return arraylist + 1;
}
void* acl_arraylist_append_ptr(void *arraylist_void, void **append_element) {
union acl_arraylist_meta *arraylist = arraylist_void;
--arraylist;
if(arraylist->len == arraylist->cap) {
acl_arraylist_resize(arraylist, 10);
if(arraylist == NULL) return NULL;
}
*append_element = (char*)(arraylist + 1) + arraylist->sizeof_one_element * arraylist->len;
++arraylist->len;
return arraylist + 1;
}
void* acl_arraylist_remove(void *arraylist_void, size_t index) {
union acl_arraylist_meta *arraylist = (union acl_arraylist_meta*)arraylist_void - 1;
char *arraylist_char = arraylist_void;
if(index != arraylist->len - 1) {
memcpy(arraylist_char + arraylist->sizeof_one_element * index, arraylist_char + arraylist->sizeof_one_element * (arraylist->len - 1), arraylist->sizeof_one_element);
}
--arraylist->len;
if(arraylist->len < arraylist->cap - 20) {
void* arraylistTmp = acl_arraylist_resize(arraylist, -10);
if(arraylistTmp != NULL) arraylist = arraylistTmp;
}
return arraylist + 1;
}
array.h:
#ifndef _acl_array_h
#define _acl_array_h
#include <stddef.h>
#include <stdlib.h>
union acl_arraylist_meta {
double dummy_double;
long double dummy_long_double;
long long dummy_long_long;
void *dummy_ptr;
void (*dummy_func_ptr)(void);
struct {
size_t len;
size_t cap;
size_t sizeof_one_element;
};
};
inline size_t acl_arraylist_len(void *arraylist) {
return ((union acl_arraylist_meta*)arraylist - 1)->len;
}
inline void acl_arraylist_free(void *arraylist) {
free((union acl_arraylist_meta*)arraylist-1);
}
void* acl_arraylist_remove(void *arraylist_void, size_t index);
void* acl_arraylist_create(size_t array_size, size_t sizeof_one_element);
void* acl_arraylist_append(void *arraylist_void, void *element);
void* acl_arraylist_append_ptr(void *arraylist_void, void **append_element);
#endif
a simple test programm:
#include <acl/array.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
void *num = acl_arraylist_create(100, sizeof(int));
for (int i = 0; i < 65536; ++i)
{
num = acl_arraylist_append(num, &i);
printf("%d\n", i);
}
}
It's worrying that your array.c source file does not include the header (acl/array.h) that declares the services that the source file defines. It means there is no cross-checking. The headers provide the glue that holds C programs together, providing cross-checking to ensure that the code using the services provided agrees with the code providing those services.
Also: Your sample program doesn't create a list — your code should not compile because num is not defined.
When resequenced a bit, the code does compile cleanly. When I added a call:
void *num = acl_arraylist_create(100, sizeof(int));
before the loop in main() and ran the code (source code acl23.c, program acl23), I got to iteration 150 before the Mac OS library said:
acl23(54767,0x10d41b5c0) malloc: *** error for object 0x7f8c40c02bb0: pointer being realloc'd was not allocated
acl23(54767,0x10d41b5c0) malloc: *** set a breakpoint in malloc_error_break to debug.
If you've got Valgrind available to you, use it.
I think your code is playing with fire (and you're getting burnt) because you're trying to combine the union arraylist_meta structure and the array data.
However, the primary problem is that when the memory is reallocated, you are not using the new value returned by acl_arraylist_append(). Change the line in the loop to:
new = acl_arraylist_append(num, &i);
and the code runs up to 65535 for me. I set the loop to stop then, rather than imposing no limit.
for (int i = 0; i < 65536; ++i).
It isn't clear how the user of your array list is going to access elements of the array. Presumably, you plan to have them convert the void * (num in the example) to an appropriate typed pointer (int *array = num;) and they can then index into the array. It's also not clear how they determine the size of the array — what the maximum index is. You've also not provided a function to free the array. The user can't do that — the pointer they have is not the one returned by one of the allocation functions (malloc(), realloc(), etc). None of these are immediately critical; we can safely assume that they were omitted from the
MCVE (Minimal, Complete, Verifiable Example — or MRE or whatever name SO now uses) you provided.
Here's my working code derived from yours — all in a single file. The changes are actually quite minor.
/*array.h:*/
#ifndef array_h
#define array_h
#include <stddef.h>
void *acl_arraylist_create(size_t array_size, size_t sizeof_one_element);
void *acl_arraylist_append(void *arraylist_void, void *element_void);
#endif
/*array.c:*/
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
/*#include <acl/array.h>*/
union arraylist_meta
{
double dummy_double;
long double dummy_long_double;
long long dummy_long_long;
void *dummy_ptr;
void (*dummy_func_ptr)(void);
struct
{
size_t len;
size_t cap;
size_t sizeof_one_element;
};
};
void *acl_arraylist_create(size_t array_size, size_t sizeof_one_element)
{
union arraylist_meta *arraylist_new = malloc(array_size * sizeof_one_element + sizeof *arraylist_new);
arraylist_new->len = array_size;
arraylist_new->cap = array_size;
arraylist_new->sizeof_one_element = sizeof_one_element;
return arraylist_new + 1;
}
void *acl_arraylist_append(void *arraylist_void, void *element)
{
union arraylist_meta *arraylist = arraylist_void;
--arraylist;
if (arraylist->len == arraylist->cap)
{
arraylist->cap = arraylist->len + 10;
arraylist = realloc(arraylist, arraylist->cap * arraylist->sizeof_one_element + sizeof *arraylist);
}
memcpy((char *)(arraylist + 1) + arraylist->sizeof_one_element * arraylist->len, element, arraylist->sizeof_one_element);
++arraylist->len;
return arraylist + 1;
}
/*a simple test programm:*/
/*#include <acl/array.h>*/
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
void *num = acl_arraylist_create(100, sizeof(int));
for (int i = 0; i < 65536; ++i)
{
num = acl_arraylist_append(num, &i);
printf("%d\n", i);
}
}
I'm not going to show the output; the numbers from 1 to 65535 are not exciting.
I distrust void * as the handle type for your array. The user could provide any pointer of their choosing as a handle and there's no way to know that it's the wrong type of pointer. Provide an opaque type instead; in the header, define:
typedef struct acl_arraylist acl_arraylist;
Then have the functions take and return an acl_arraylist *. The client code doesn't need to know what's in it. Your code in array.c might wrap the union arraylist_meta value into a structure:
struct acl_arraylist
{
union arraylist_meta array;
};
You can then play in much the same way you did before. But the user has to work to pass an arbitrary pointer to the functions — sufficiently hard that they won't get it wrong.
The new pointer returned from acl_arraylist_resize is ignored in acl_arraylist_append_ptr.
modified code:
void* acl_arraylist_append_ptr(void *arraylist_void, void **append_element) {
union acl_arraylist_meta *arraylist = arraylist_void;
--arraylist;
if(arraylist->len == arraylist->cap) {
arraylist = acl_arraylist_resize(arraylist, 10);// this line was modified
if(arraylist == NULL) return NULL;
}
*append_element = (char*)(arraylist + 1) + arraylist->sizeof_one_element * arraylist->len;
++arraylist->len;
return arraylist + 1;
}
Related
I am new in learning C. I have an issue in returning double star pointer from the function.
This is my code.
#include <stdio.h>
#include <stdbool.h>
#include "api.h"
void init() {
// You can initiate and calculate things here
}
/**
* Return the given list in reversed order. Each element in the given list contains a single character.
*
* typedef struct {
* int count;
* const char * * elements;
* } string_list;
*
* list_of_chars: string_list
*
* returns: string_list
*/
string_list reverse(string_list list_of_chars) {
// Write your code here
char X[list_of_chars.count];
//X[0] = *list_of_chars.elements[0];
for (int i = 0; i < list_of_chars.count;i++){
X[i] = *list_of_chars.elements[i];
}
printf("%c", X[0]);
string_list return_value = {
.count = 0,
.elements = &X[0],
};
return return_value;
}
But I am getting initialization of 'const char **' from incompatible pointer type 'char *'. I tried multiple solutions but non of them worked.
Side note: As I mentioned in the top comments, I was limited to what I could do on mobile. I'm back at my desk.
Issues were:
X is function scoped, so it goes out of scope when the function returns. We need to use malloc [so we need stdlib.h]
Because elements is a const char **, then we need const char **X
We need to use [should use] strdup to duplicate the elements.
Otherwise, both lists will share the same data. This may the desired intent. But, it's not clear from the problem description what the correct code should be.
Most lists should be fully independent from one another. The original code does not do this. So, the lists are sharing the data. But, if that's true, why bother to create a separate list? We could just "reverse" it by indexing in the reverse direction without creating a new list:
for (int i = list.count - 1; i >= 0; --i)
So, I've chosen to duplicate the strings. Original behavior (shared strings) when compiled with -DNODUP.
Here's the refactored code:
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#if 0
#include "api.h"
#else
typedef struct {
int count;
const char **elements;
} string_list;
#endif
void
init()
{
// You can initiate and calculate things here
}
/**
* Return the given list in reversed order. Each element in the given list contains a single character.
*
* typedef struct {
* int count;
* const char * * elements;
* } string_list;
*
* list_of_chars: string_list
*
* returns: string_list
*/
string_list
reverse(string_list list)
{
const char **X = malloc(sizeof(*X) * list.count);
// share the strings
#if NODUP
for (int i = 0; i < list.count; i++)
X[list.count - 1 - i] = list.elements[i];
// make lists independent (more usual/expected)
#else
for (int i = 0; i < list.count; i++)
X[list.count - 1 - i] = strdup(list.elements[i]);
#endif
string_list ret = {
.count = list.count,
.elements = X,
};
return ret;
}
UPDATE:
In the link above was the exercise page where we can choose GCC for C. I pasted your code exactly to the website bit still see same errors.
Okay, finally ... ;-)
The website uses an ancient version of the C standard (e.g. C99). This does not have strdup.
The website will [forcibly] do a #include "api.h" before including the code, so there is a conflict with the definition I used.
Here is the corrected code (which runs successfully on the website):
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#if 1
#include "api.h"
#else
typedef struct {
int count;
const char **elements;
} string_list;
#endif
void
init()
{
// You can initiate and calculate things here
}
/**
* Return the given list in reversed order. Each element in the given list contains a single character.
*
* typedef struct {
* int count;
* const char * * elements;
* } string_list;
*
* list_of_chars: string_list
*
* returns: string_list
*/
string_list
reverse(string_list list)
{
const char **X = malloc(sizeof(*X) * list.count);
// share the strings
#if 1
for (int i = 0; i < list.count; i++)
X[list.count - 1 - i] = list.elements[i];
// make lists independent (more usual/expected)
#else
for (int i = 0; i < list.count; i++)
X[list.count - 1 - i] = strdup(list.elements[i]);
#endif
string_list ret = {
.count = list.count,
.elements = X,
};
return ret;
}
Side note: I'd get a good book on C and study that to get more basic knowledge of C. Trying to use "competition" websites isn't the best way, IMO.
A number of the issues you've seen (but did not understand) would have been obvious with a better basic understanding of C syntax and semantics.
Here's a list: The Definitive C Book Guide and List
I'm doing an assignment for my data structures class and I have very little experience with C structures and C in general.
This is the .h file that I was given to do the assignment:
#ifndef C101IntVec
#define C101IntVec
typedef struct IntVecNode* IntVec;
static const int intInitCap = 4;
int intTop(IntVec myVec);
int intData(IntVec myVec, int i);
int intSize(IntVec myVec);
int intCapacity(IntVec myVec);
IntVec intMakeEmptyVec(void);
void intVecPush(IntVec myVec, int newE);
void intVecPop(IntVec myVec);
#endif
This is the .c implementation that I've made:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "intVec.h"
typedef struct IntVecNode {
int* data;
int sz; // Number of elements that contain data
int capacity; // How much is allocated to the array
} IntVecNode;
typedef struct IntVecNode* IntVec;
//static const int intInitCap = 4;
int intTop(IntVec myVec) {
return *myVec->data;
}
int intData(IntVec myVec, int i) {
return *(myVec->data + i);
}
int intSize(IntVec myVec) {
return myVec->sz;
}
int intCapacity(IntVec myVec) {
return myVec->capacity;
}
IntVec intMakeEmptyVec(void) {
IntVec newVec = malloc(sizeof(struct IntVecNode));
newVec->data = malloc(intInitCap * sizeof(int));
newVec->sz = 0;
newVec->capacity = intInitCap;
return newVec;
}
void intVecPush(IntVec myVec, int newE) {
if (myVec->sz >= myVec->capacity) {
int newCap = myVec->capacity * 2;
myVec->data = realloc(myVec->data, newCap * sizeof(int));
} else {
for (int i = 0; i < myVec->capacity; i++) {
*(myVec->data + i) = *(myVec->data + i + 1);
}
myVec->data = &newE;
}
myVec->sz++;
}
void intVecPop(IntVec myVec) {
for (int i = 0; i < myVec->capacity; i++) {
*(myVec->data - i) = *(myVec->data - i + 1);
}
myVec->sz--;
}
This is the test file:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "intVec.c"
int main() {
struct IntVec v;
v.intVecPush(v,0);
return 0;
}
Every time I run the test file, I get the error:
test.c:7:16: error: variable has incomplete type 'struct IntVec'
struct IntVec v;
^
test.c:7:9: note: forward declaration of 'struct IntVec'
struct IntVec v;
^
1 error generated.
I've tried changing the #include "intVec.c" to "intVec.h" in the test file, however that produces the same error. What would I need to change in order to not get this error?
There is no structure definition struct IntVec.
So the compiler is unable to define the object v
struct IntVec v;
I think you mean
IntVec v;
And this call
v.intVecPush(v,0);
is invalid and does not make sense. I think there should be something like
IntVec v = intMakeEmptyVec();
intVecPush(v,0);
instead of
struct IntVec v;
v.intVecPush(v,0);
Also it is a bad idea to include the whole module in another module. You should place the structure definition in the header and include this header in the compilation unit with main.
That is move these definitions
typedef struct IntVecNode {
int* data;
int sz; // Number of elements that contain data
int capacity; // How much is allocated to the array
} IntVecNode;
typedef struct IntVecNode* IntVec;
in the header.
I tried to write a vector in c using memory operations.Compiler shows no errors but if I try to print an element from the vector it simply crashes. And whenever I try to print destination variable (printf((int) destination)) the program crashes again.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef struct{
void* elemList;
int elemSize;
int maxSize;
int curSize;
}myvector;
void initVec(myvector * vec, int typeSize){
vec->curSize = 0;
vec->maxSize = 10;
vec->elemSize =typeSize;
vec->elemList = malloc(10*sizeof(typeSize));
}
void add(myvector * vec, void* elem){
if(vec->curSize >= vec->maxSize){
vec->elemList = realloc(vec->elemList, vec->maxSize*2);
}
memcpy(&vec->elemList[vec->curSize],elem,vec->elemSize);
}
void get(myvector * vec, int index, void* destination){
if(index > vec->curSize || index < 0){
printf("Invalid Index");
return;
}
destination = malloc(vec->elemSize);
memcpy(destination,&vec->elemList[index], vec->elemSize);
}
int main()
{
myvector newVec;
initVec(&newVec,sizeof(int));
int a = 5;
add(&newVec,&a);
int* b;
get(&newVec,0,b);
printf(*b);//this is where the program crashes
return 0;
}
Basically the pointer in the get is not handled correctly. It's being passed by value so a copy of the pointer is made, the copy is modified (memory allocation is done for this copy), but the original pointer once you quit the get method is not pointing to a valid memory. You have to pass the address of the pointer. Following is a modified code (note the double ** in the destination in the get method). Basically I pass the address of the "destination" pointer instead of the pointer itself. Additionally I fixed the line sizeof(typeSize) .. it should be typeSize only since you are already calling the initVec method with sizeof operator.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef struct{
void* elemList;
int elemSize;
int maxSize;
int curSize;
}myvector;
void initVec(myvector * vec, int typeSize){
vec->curSize = 0;
vec->maxSize = 10;
vec->elemSize = typeSize;
vec->elemList = malloc(vec->maxSize*typeSize);
}
void add(myvector * vec, void* elem){
if(vec->curSize >= vec->maxSize)
{
vec->elemList = realloc(vec->elemList, vec->maxSize*2);
}
memcpy(&vec->elemList[vec->curSize], elem, vec->elemSize);
vec->curSize++;
}
void get(myvector * vec, int index, void** destination){
if(index > vec->curSize || index < 0)
{
printf("Invalid Index");
return;
}
*destination = malloc(vec->elemSize);
memcpy(*destination, &vec->elemList[index], vec->elemSize);
}
int main()
{
myvector newVec;
initVec(&newVec,sizeof(int));
int a = 5;
add(&newVec,&a);
int* b;
get(&newVec, 0, &b);
printf("value of b is %d\n", *b); // This works correctly now
return 0;
}
A couple of issues with the code :
vec->elemList = malloc(10*sizeof(typeSize)); should be vec->elemList = malloc(10*typeSize);
If you would like get to create a pointer to int I would recommend either defining it like int* get(myvector * vec, int index) and return a newly allocated pointer to int or in the main function use :
int b;
get(&newVec, 0, &b);
the latter will also avoid memory leaks.
printf(*b); is wrong as you are passing an int and it expects a char* use either printf("%d", b); if b is an int or printf("%d", b);if b is aint`
you are using malloc a lot but no free. In this particular program you don't get memory leaks as the OS will reclaim all memory when main returns. But think early about a function to clear your vector and.
*b shouldn't be a valid pointer to string, so it will cause crash.
Try printing it by printf("%d",*b);
To make it better, you should free the buffer that are allocated by malloc.
UPDATE
The get function is wrong since it throws away the buffer allocated to destination
get function and main function should be like this:
void get(myvector * vec, int index, void** destination){
if(index > vec->curSize || index < 0){
printf("Invalid Index");
return;
}
*destination = malloc(vec->elemSize);
memcpy(*destination,&vec->elemList[index], vec->elemSize);
}
int main()
{
myvector newVec;
initVec(&newVec,sizeof(int));
int a = 5;
add(&newVec,&a);
int* b;
get(&newVec,0,&b);
printf("%d",*b);//this is where the program crashes
return 0;
}
But this still gives me Segmentation Fault. I'm working on.
UPDATE 2
You should think about the size of each elements.
You also forget the size information in add function.
This code should work if we don't care about memory leak.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef struct{
void* elemList;
int elemSize;
int maxSize;
int curSize;
}myvector;
void initVec(myvector * vec, int typeSize){
vec->curSize = 0;
vec->maxSize = 10;
vec->elemSize =typeSize;
vec->elemList = malloc(vec->maxSize*vec->elemSize);
}
void add(myvector * vec, void* elem){
if(vec->curSize >= vec->maxSize){
vec->elemList = realloc(vec->elemList, vec->elemSize * vec->maxSize*2);
vec->maxSize *= 2;
}
memcpy(vec->elemList + vec->curSize * vec->elemSize,elem,vec->elemSize);
vec->curSize++;
}
void get(myvector * vec, int index, void** destination){
if(index >= vec->curSize || index < 0){
printf("Invalid Index");
return;
}
*destination = malloc(vec->elemSize);
memcpy(*destination,vec->elemList + index * vec->elemSize, vec->elemSize);
}
int main()
{
myvector newVec;
initVec(&newVec,sizeof(int));
int a = 5;
add(&newVec,&a);
int* b;
get(&newVec,0,(void**)&b);
printf("%d",*b);
return 0;
}
I have such a code
#include <dlfcn.h>
#include <stdlib.h>
#include "timer.h"
#define SIZE 9000
void *memorylib;
void *arraylib;
typedef struct {
int rows;
int columns;
long **d;
} array;
int main(){
memorylib = dlopen("libmemory.so", RTLD_LAZY);
if(!memorylib){
exit(-1);
}
arraylib = dlopen("libarray.so",RTLD_LAZY);
if(!arraylib) {
exit(-1);
}
typedef void (*memory_initialize)(long);
typedef void * (*memory_add)(long);
typedef array *(*memory_allocate)(int,int);
memory_add add = (memory_add) dlsym(memorylib,"add");
memory_initialize initialize = (memory_initialize) dlsym(memorylib, "initialize");
memory_allocate allocate = (memory_allocate) dlsym(arraylib,"allocate");
initialize(SIZE*sizeof(int)/1024 + 1);
int rows = 10;
int columns = 10;
array *m = allocate(rows,columns);
dlclose(memorylib);
dlclose(arraylib);
return 0;
}
and initialize method works, but when I try to use allocate method I get an error
symbol lookup error: /usr/local/lib/libarray.so: undefined symbol: add
I use this add method in my allocate method which comes from memory.h
#include <stdio.h>
#include <stdlib.h>
#include "array.h"
#include "memory.h"
array * allocate(int rows, int columns) {
// printf("%i",sizeof(array));
array *m = (array *) add(sizeof(array));
m->rows = rows;
m->columns = columns;
int i;
long **d = (long**)add(rows* sizeof(long*));
for(i=0;i< rows;i++) {
d[i] = (long *) add(columns * sizeof(long));
}
m->d = d;
return m;
}
How to fix it ? It's probably fail, because I don't load library dynamically to file containing allocate method ?
You need to use the flag RTLD_GLOBAL when loading libmemory.so so that symbols in it will be available for use by subsequently loaded libraries (such as libarray.so). By default, symbols in a library are only visible to that library and to dlsym calls using that library.
I have the following code in a header file:
#ifndef BUFFER_H
#define BUFFER_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct c_buff
{
void *buffer; // data buffer
void *buffer_end; // end of data buffer
size_t capacity; // maximum number of items in the buffer
size_t count; // number of items in the buffer
size_t sz; // size of each item in the buffer
void *head; // pointer to head
void *tail; // pointer to tail
};
void cb_init(c_buff *cb, size_t capacity, size_t sz)
{
cb->buffer = malloc(capacity * sz);
if(cb->buffer == NULL) {
// handle error
}
cb->buffer_end = (char *)cb->buffer + capacity * sz;
cb->capacity = capacity;
cb->count = 0;
cb->sz = sz;
cb->head = cb->buffer;
cb->tail = cb->buffer;
}
#endif
And the following c file
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <common.h>
#include <usart.h>
#include <buffer.h>
struct c_buff usart_buffer;
struct c_buff *usart_buffer_ptr;
cb_init(usart_buffer_ptr, USART_BUFFER_SIZE, sizeof(char));
void initUSART(void) {
SETBIT(UCSR0A, UDRE0);
//SETBIT(UCSR0A, U2X0);
SETBIT(UCSR0C, UCSZ01);
SETBIT(UCSR0C, UCSZ00);
UBRR0 = 25;
SETBIT(UCSR0B, RXCIE0);
SETBIT(UCSR0B, TXCIE0);
SETBIT(UCSR0B, RXEN0);
SETBIT(UCSR0B, TXEN0);
}
ISR(USART_RX_vect) {
char data;
data = UDR0;
UDR0 = data;
}
ISR(USART_TX_vect) {
}
When I try to compile this I get an error that points to this line:
cb_init(usart_buffer_ptr, USART_BUFFER_SIZE, sizeof(char));
And it just says "error: expected ')' before numeric constant".
Google tells me it's some kind of preprocessor error. But I don't see how that could be the case.
I'm new to C so I apologize if it is something totally obvious.
You can't have a naked function call at the top level.
cb_init(usart_buffer_ptr, USART_BUFFER_SIZE, sizeof(char));
is a naked function call. Move that inside main().
You can't run function in global scope. It has to be done in main:
int main(int argc, char *argv[] {
cb_init(usart_buffer_ptr, USART_BUFFER_SIZE, sizeof(char));
}
The problem is that you're attempting to execute a method at the file level.
cb_init(usart_buffer_ptr, USART_BUFFER_SIZE, sizeof(char));
The C language only allows declarations / definitions at this level not actual executed statements. This call needs to be moved into a function definition.