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.
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
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;
}
I have a large code that I need to pass a struct to a CUDA kernel that has a larger number of ints for parameters and a vector. I can't figure out how to pass the struct to the CUDA kernel. I've copied it to the device, but get the following error when trying to compile:
test_gpu.cpp:63:17: error: invalid operands to binary expression ('void (*)(Test)' and 'dim3')
computeTotal<<dimGrid, dimBlock>>(test_Device);
test_gpu.cpp:63:36: error: invalid operands to binary expression ('dim3' and 'Test *')
computeTotal<<dimGrid, dimBlock>>(test_Device);
Attached is a small almost working example of the code, any ideas?
#include <stdio.h>
#include <stdlib.h>
#include <cuda_runtime_api.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <device_functions.h>
#include <device_launch_parameters.h>
#include <vector>
#include <string>
typedef struct Test{
int x;
int y;
int z;
std::vector<int> vector;
std::string string;
}Test;
Test test;
__device__ void addvector(Test test, int i){
test.x += test.vector[i];
test.y += test.vector[i+1];
test.z += test.vector[i+2];
}
__global__ void computeTotal(Test test){
for (int tID = threadIdx.x; tID < threadIdx.x; ++tID )
addvector(test, tID);
}
int main()
{
Test test_Host;
int vector_size = 512;
test_Host.x = test_Host.y = test_Host.z = 0;
for (int i=0; i < vector_size; ++i)
{
test_Host.vector.push_back(rand());
}
Test* test_Device;
int size = sizeof(test_Host);
cudaMalloc((void**)&test_Device, size);
cudaMemcpy(test_Device, &test_Host, size, cudaMemcpyHostToDevice);
dim3 dimBlock(16);
dim3 dimGrid(1);
computeTotal<<dimGrid, dimBlock>>(test_Device);
return 0;
}
Items from C++ standard libraries aren't generally/normally usable in CUDA device code. The documentation support for this is here.
For this particular case, it means you may have trouble with either std::vector or std::string. One possible workaround is to replace these with ordinary C-style arrays:
#define MAX_VEC_SIZE 512
#define MAX_STR_SIZE 512
typedef struct Test{
int x;
int y;
int z;
int vec[MAX_VEC_SIZE];
char str[MAX_STR_SIZE];
}Test;
This will of course necessitate changes elsewhere in your code.
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'm trying to use a queue in my program, but it won't compile and I don't know why. The relevant part of the code is as follows.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#ifndef CUSTOMER
#define CUSTOMER
typedef int bool;
int r;
typedef struct{
int arrival;
int leaving;
} Customer;
static const int MAX_LENGTH = 100;
typedef struct{
int head;
int length;
Customer customer[MAX_LENGTH];
} CustomerLine;
void initializeQueue(CustomerLine* queue)
{
(*queue).head = 0;
(*queue).length = 0;
}
bool hasNext(CustomerLine* queue)
{
return (*queue).length > 0;
}
bool isFull(CustomerLine* queue)
{
return (*queue).length == MAX_LENGTH;
}
bool enqueue(CustomerLine* queue, Customer* customer)
{
if(isFull(queue))
return 0;
int index = ((*queue).head + (*queue).length) % MAX_LENGTH;
(*queue).customer[index] = *customer;
(*queue).length++;
return 1;
}
Customer* dequeue(CustomerLine* queue)
{
if(!hasNext(queue))
return 0;
Customer* result = &(*queue).customer[(*queue).head];
(*queue).length--;
(*queue).head = ((*queue).head + 1) % MAX_LENGTH;
return result;
}
The error says "Variably Modified 'customer' at file scope" I am a beginner at programming and just doing this is starting to get beyond my abilities so any help would be very much appreciated.
The line
static const int MAX_LENGTH = 100
is the problem. Replace it with
#define MAX_LENGTH 100
See why here and more explanations here or here or again here.
Furthermore:
You need an #endif after the #ifndef.
You need a main function somewhere.
In C, const means read-only, not constant and usable just like a macro. You cannot use a variable to specify the dimension of an array as you do here:
static const int MAX_LENGTH = 100;
typedef struct{
int head;
int length;
Customer customer[MAX_LENGTH]; /* Wrong. MAX_LENGTH is not a compile time constant. */
} CustomerLine;