I'm interested in how you can write data in a particular structure to a pre-allocated memory block.
The idea is to write down the render commands and then read them in a loop. The problem is that allocating and deleting memory every cycle, which is 60 times per second is bad and I want to ask how can I write and read different types of data to the buffer.
example:
struct cmd_viewport {
int x, y, w, h;
};
struct cmd_line {
int x0, y0, x1, y1;
unsigned int width;
};
void* buffer_alloc(void* buffer, size_t offset, size_t size) {
...
}
void* buffer_get_ptr(void* buffer, size_t offset) {
...
}
int main(int argc, char* argv) {
void* cmd_buffer;
struct cmd_viewport* viewport;
struct cmd_line* line;
struct cmd_line* line2;
cmd_buffer = malloc(1024);
if (cmd_buffer == NULL) {
return EXIT_FAILURE;
}
viewport = (struct cmd_viewport*)buffer_alloc(cmd_buffer, 0, sizeof(struct cmd_viewport));
line = (struct cmd_line*)buffer_alloc(cmd_buffer, sizeof(struct cmd_viewport), sizeof(struct cmd_line));
/* it must be a direct write to the cmd_buffer memory location */
viewport->x = 0;
viewport->y = 0;
viewport->w = 800;
viewport->h = 600;
line->x0 = 100;
line->y0 = 100;
line->x1 = 300;
line->y1 = 400;
line->width = 2;
line2 = (struct cmd_line*)buffer_get_ptr(cmd_buffer, sizeof(struct cmd_viewport));
printf("line->width = %d\n", line2->width);
free(cmd_buffer);
return EXIT_SUCCESS;
}
How can you make a void* buffer cast from a specific offset to any data type ?
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include <math.h>
#include <time.h>
#define RAND(lower,upper) (rand()%(upper-lower+1))+lower
int power(int base, int exp)
{
int result=1;
while (exp != 0)
{
result *= base;
--exp;
}
return result;
}
int isKthBitSet(int n, int k)//from right, 1<=k<=n
{
int new_num = n >> (k - 1);
// if it results to '1' then bit is set,
// else it results to '0' bit is unset
return (new_num & 1);
}
struct Astructure{
uint16_t bitmap;
uint32_t a;
uint32_t b;
char str[10];
uint16_t d;
}__attribute__((packed));
int main()
{
struct Astructure abitmap;
abitmap.bitmap = 0;
char buffer[(sizeof(struct Astructure))];
abitmap.a = 52;
abitmap.b = 16;
char c[10]={"ramya"};
strcpy(abitmap.str, c);
abitmap.d = 59;
char ch;
srand(time(0));
for(uint8_t position =1;position<5;position++)
{
int random10 = RAND(0,1);
if(random10==1)
{
int value = power(2,position-1);
abitmap.bitmap = abitmap.bitmap | value;
}
}
memcpy(buffer, (char *)&abitmap.bitmap, sizeof(abitmap.bitmap)+1);
uint8_t temp4 = isKthBitSet(abitmap.bitmap,4);
uint8_t temp3 = isKthBitSet(abitmap.bitmap,3);
uint8_t temp2 = isKthBitSet(abitmap.bitmap,2);
uint8_t temp1 = isKthBitSet(abitmap.bitmap,1);
uint8_t previousLength = sizeof(abitmap.bitmap);
if(temp4){
//add a to buffer
memcpy(buffer + previousLength, (void *)&abitmap.a, sizeof(abitmap.a)+1);
previousLength += sizeof(abitmap.a);
}
if(temp3){
//add b to buffer
memcpy(buffer + previousLength, (void *)&abitmap.b, sizeof(abitmap.b)+1);
previousLength += sizeof(abitmap.b);
}
if(temp2){
//add c to buffer
memcpy(buffer + previousLength, (void *)&abitmap.str, sizeof(abitmap.str)+1);
previousLength += sizeof(abitmap.str);
}
if(temp1){
//add d to buffer
memcpy(buffer + previousLength, (char *)&abitmap.d, sizeof(abitmap.d)+1);
previousLength += sizeof(abitmap.d);
}
//SHOW BUFFER
previousLength = sizeof(abitmap.bitmap);
uint32_t a;
uint32_t b;
char str[10];
uint16_t d;
if(temp4){
memcpy(&a , (void *) buffer+previousLength , sizeof(abitmap.a)+1);//
printf("a = %d\t",a);
previousLength += sizeof(a);
}
if(temp3){
memcpy(&b , (void *) buffer+previousLength , sizeof(abitmap.b)+1);
printf("b = %d\t",b);
previousLength += sizeof(b);
}
if(temp2){
memcpy(str , (void *) buffer+previousLength , sizeof(abitmap.str)+1);//memccpy
printf("string = %s\t",str);
previousLength += sizeof(str);
}
if(temp1){
memcpy(&d , (void *) buffer+previousLength , sizeof(abitmap.d)+1);
printf("d = %d\t",d);
previousLength += sizeof(d);
}
printf("\n");
}
I trying to copy some variables to my buffer. The variables I want to add in the buffer is picked at random. Here I gave the size of my buffer before hand to the size of my structure. But as per my program I may not be adding all my variables in the buffer. So its a waste.
So How am I supposed to declare my buffer here.
if my replace this
char buffer[(sizeof(struct Astructure))];
to
char *buffer;
this
I get below error.
a = 52 string = ramya
*** stack smashing detected ***: terminated
Aborted (core dumped)
I dont want to waste the size of my buffer in here, giving the whole size of structure. so what do i do.
If you want to allocate only the required memory:
typedef struct
{
size_t length;
unsigned char data[];
}buff_t;
buff_t *addtobuffer(buff_t *buff, const void *data, size_t size)
{
size_t pos = buff ? buff -> length : 0;
buff = realloc(buff, pos + size + sizeof(*buff));
if(buff)
{
memcpy(buff -> data + pos, data, size);
buff -> length = pos + size;
}
return buff;
}
and example usage:
buff_t *buffer = NULL;
/* ... */
if(temp4)
{
buff_t *tmp = addtobuffer(buffer, &abitmap.a, sizeof(abitmap.a)+1);
if(!tmp) { /* error handling */}
buffer = tmp;
/*...*/
}
I am using cygwin, I am getting after the output in the last raw aborted (dumped core) I uploaded an image of the output this is my code in the code. I have Array.h, Array.c, Table.c, Table.h and main.c.
Code: table header file Table.h:
#ifndef EX4_TABLE_H
#define EX4_TABLE_H
#include "Array.h"
typedef struct Table *TableP;
TableP TableCreate();
void TableDestroy(TableP p);
char* TableRowName(TableP p, int i);
char* TableColumnName(TableP p, int i);
int TableNumColumns(TableP p);
int TableNumRows(TableP p);
Element TableGet(TableP p, int i, int j);
void TableSet(TableP p, int i, int j, Element val);
void TableAddRow(TableP p, char *name);
void TableAddColumn(TableP p, char *name, Element (*cpy)(Element), void(*fre)(Element));
#endif
Table C file Table.c:
#include "Table.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct Table {
Array *arr;
int numOfCul;
char **name_cul;
int rowSize;
char **name_row;
};
TableP TableCreate() {
TableP p = (TableP)malloc(sizeof(struct Table));
if (!p) {
fprintf(stderr, "%s/%u: failed to allocate %lu bytes. Aborting\n\n", __FILE__, __LINE__, sizeof(struct Table));
exit(0);
}
p->name_cul = NULL;
p->name_row = NULL;
p->arr = NULL;
p->numOfCul = 0;
p->rowSize = 0;
return p;
}
void TableDestroy(TableP p) {
for (int i = 0; i < p->numOfCul; i++) {
ArrayDestroy(p->arr[i]);
free(p->name_cul[i]);
for (int j = 0; j < p->rowSize; j++) {
free(p->name_row[j]);
}
}
free(p);
}
void TableAddRow(TableP p, char *name) {
p->rowSize = p->rowSize + 1;
p->name_row = (char **)realloc(p->name_row, sizeof(char*) * p->rowSize);
p->name_row[p->rowSize - 1] = (char *)malloc(sizeof(char) * 8);
strcpy(p->name_row[p->rowSize-1], name);
for (int i = 0; i < p->numOfCul; i++) {
ArrayResize(p->arr[i], p->rowSize);
}
}
void TableAddColumn(TableP p, char *name, Element (*cpy)(Element), void(*fre)(Element)) {
p->numOfCul = p->numOfCul + 1;
p->name_cul = (char **)realloc(p->name_cul, sizeof(char*) * p->numOfCul);
p->name_cul[p->numOfCul - 1] = (char *)malloc(sizeof(char) * 8);
strcpy(p->name_cul[p->numOfCul - 1], name);
p->arr = (Array *)realloc(p->arr, sizeof(Array));
p->arr[p->numOfCul - 1] = ArrayCreate(p->rowSize, cpy, free);
}
void TableSet(TableP p, int i, int j, Element val) {
if (i > p->numOfCul || j > p->rowSize) {
printf("number not in range \n");
exit(0);
}
ArraySet(p->arr[i], j, val);
}
Element TableGet(TableP p, int i, int j) {
if (i > p->numOfCul || j > p->rowSize) {
printf("number not in range \n");
exit(0);
}
return ArrayGet(p->arr[i], j);
}
int TableNumRows(TableP p) {
return p->rowSize;
}
int TableNumColumns(TableP p) {
return p->numOfCul;
}
char *TableRowName(TableP p, int i) {
if (p->rowSize < i) {
printf("num row is wrong\n");
exit(1);
}
return p->name_row[i];
}
char *TableColumnName(TableP p, int i) {
if (p->rowSize < i) {
printf("num row is wrong\n");
exit(1);
}
return p->name_cul[i];
}
File Array.h:
#ifndef EX4_ARRAY_H
#define EX4_ARRAY_H
typedef void *Element;
typedef struct Array *Array;
/*
* Array constructor, expects to get the size of the array, a copy function for the type of elements to be kept
* and a free function. Array is initialized with NULL values
*/
Array ArrayCreate(unsigned int n, Element (*cpy)(Element), void(*fre)(Element));
/*
* Array destractor
*/
void ArrayDestroy(Array a);
/*
* Keeps a copy of element e in index i. Will print an error message and terminate the program if i is out of range.
* The element that was kept in index i (if there is any) will be deleted
*/
void ArraySet(Array a, unsigned int i, Element e);
/*
* Returns the element in index i (NULL if there is no element stored). Will print an error message and terminate the
* program if i is out of range.
*/
Element ArrayGet(Array a, unsigned int i);
/*
* Returns the size of the array
*/
unsigned int ArraySize(Array a);
/*
* Changes the size of the array. If the new size if hiigher than current size then empty cells will be added.
* If the new size is smaller, then the items at the end of the array will be deleted.
* newn can be 0 (resulting with an empty array).
*/
void ArrayResize(Array a, unsigned int newn);
#endif
File Array.c:
#include <stdio.h>
#include <stdlib.h>
#include "Array.h"
/***********************************************************************************************************************/
struct Array {
Element *elements;
unsigned int num_elements;
Element (*cpy)(Element);
void (*fre)(Element);
};
/***********************************************************************************************************************/
Array ArrayCreate(unsigned int n, Element (*cpy)(Element), void(*fre)(Element)) {
Array array = (Array)calloc(1, sizeof(struct Array));
if (!array) {
fprintf(stderr, "%s/%u: failed to allocate %lu bytes. Aborting\n\n", __FILE__, __LINE__, sizeof(struct Array));
exit(-1);
}
array->num_elements = n;
array->elements = (Element)calloc(array->num_elements, sizeof(Element));
if (!array->elements) {
fprintf(stderr, "%s/%u: failed to allocate %lu bytes. Aborting\n\n", __FILE__, __LINE__, sizeof(Element)*array->num_elements);
exit(-1);
}
array->cpy = cpy;
array->fre = fre;
return array;
}
/***********************************************************************************************************************/
void ArrayDestroy(Array a) {
ArrayResize(a, 0);
free(a->elements);
free(a);
}
/***********************************************************************************************************************/
void ArraySet(Array a, unsigned int i, Element e) {
if (i >= a->num_elements) {
fprintf(stderr, "\nError, %s: tried to set an element in index %u, array size is %u. Aborting\n\n", __FUNCTION__, i, a->num_elements);
exit(-1);
}
if (a->elements[i])
a->fre(a->elements[i]);
a->elements[i] = a->cpy(e);
}
/***********************************************************************************************************************/
Element ArrayGet(Array a, unsigned int i) {
if (i >= a->num_elements) {
fprintf(stderr, "\nError, %s: tried to get an element from index %u, array size is %u. Aborting\n\n", __FUNCTION__, i, a->num_elements);
exit(-1);
}
return a->elements[i];
}
/***********************************************************************************************************************/
unsigned int ArraySize(Array a) {
return a->num_elements;
}
/***********************************************************************************************************************/
void ArrayResize(Array a, unsigned int newn) {
// If the new size is smaller than the older one then remove the extra elements
if (newn < a->num_elements) {
for (;a->num_elements > newn; a->num_elements--) {
a->fre(a->elements[a->num_elements - 1]);
}
}
// If the new size is 0 then free a->elements and leave
if (newn == 0) {
free(a->elements);
a->elements = NULL;
return;
}
a->elements = (Element)realloc(a->elements, sizeof(Element) * newn);
if (!a->elements) {
fprintf(stderr, "%s/%u: failed to allocate %lu bytes. Aborting\n\n", __FILE__, __LINE__, sizeof(Element)*newn);
exit(-1);
}
// If the new size is larger than the old size - fill the newly added cells with NULL
if (newn > a->num_elements) {
for (; a->num_elements < newn; a->num_elements++)
a->elements[a->num_elements] = NULL;
}
}
File main.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Table.h"
/***********************************************************************************************************************/
Element str_cpy(Element e) {
char *s = (char *)malloc(sizeof(char) * (strlen((char*)e) + 1));
if (!s) {
fprintf(stderr, "\n%s/%u: failed to allocate %lu bytes. Aborting\n\n", __FILE__, __LINE__, sizeof(char)*(strlen((char*)e)+1));
exit(-1);
}
strcpy(s, (char*)e);
return (Element)s;
}
/***********************************************************************************************************************/
Element int_cpy(Element e) {
int *i = (int *)malloc(sizeof(int));
if (!i) {
fprintf(stderr, "\n%s/%u: failed to allocate %lu bytes. Aborting\n\n", __FILE__, __LINE__, sizeof(int));
exit(-1);
}
*i = *((int *)e);
return (Element)i;
}
/***********************************************************************************************************************/
int main() {
TableP t = TableCreate();
TableAddColumn(t, "Int1", int_cpy, free);
TableAddColumn(t, "Char1", str_cpy, free);
TableAddColumn(t, "Int2", int_cpy, free);
TableAddColumn(t, "Char2", str_cpy, free);
srand(42);
for (int i = 0; i < 5; i++) {
int i1 = 500 + i, i2 = i1 * i1;
char str[32];
sprintf(str, "r%d", i);
TableAddRow(t, str);
TableSet(t, 0, i, &i1);
sprintf(str, "Hello_%d", i1);
TableSet(t, 1, i, str);
TableSet(t, 2, i, &i2);
sprintf(str, "Bye_%d", i2);
TableSet(t, 3, i, str);
}
for (int i = 0; i < TableNumColumns(t); i++) {
printf("\t%s", TableColumnName(t, i));
}
printf("\n");
for (int r = 0; r < TableNumRows(t); r++) {
printf("%s", TableRowName(t, r));
for (int c = 0; c < TableNumColumns(t); c++) {
if (c == 0 || c == 2)
printf("\t%d", *(int *)(TableGet(t, c, r)));
else
printf("\t%s", (const char *)(TableGet(t, c, r)));
}
printf("\n");
}
TableDestroy(t);
return 0;
}
output:
There are multiple problems in the code:
you test for malloc failures but not everywhere, nor do you check for realloc failures. You should write wrappers or macros for these functions that perform the test and exit gracefully upon failure. This would make the calling code more readable.
in TableDestroy, the 2 for loops should not be nested. This causes multiple free for the same pointers.
when setting column and row names, you should use strdup() instead of allocating a harcoded length of 8 and using strcpy without checking that the name fits.
in TableAddColumn the array pointed to by p->arr is not resized to the new number of entries. You should have:
p->arr = (Array *)realloc(p->arr, sizeof(Array) * p->numOfCul);
the test in TableSet and TableGet is incorrect: you should use >= instead of >, report the error to stderr and exit with a non zero status:
if (i >= p->numOfCul || j >= p->rowSize) {
fprintf(stderr, "table coordinates out of range: %d,%d\n", i, j);
exit(1);
}
same problem in TableRowName and TableColumnName
hiding pointers behind typedefs is confusing and error prone. Especially confusing is the typedef typedef struct Array *Array;
I want to pass a structure to a function and store value in the structure's element. Here is my code.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef struct {
uint32_t len;
uint16_t *arr;
} seq;
void write_seq(seq *q, int val)
{
// How to implement this function?
uint16_t *tmp;
tmp = (uint16_t *)malloc(sizeof(uint16_t));
*tmp = val;
*(q->arr + q->len) = *tmp;
q->len += 1;
}
int main(int argc, char *argv[])
{
seq q;
q.len = 0;
q.arr = NULL;
int i;
for (i = 0; i < 10; i++) {
write_seq(&q, i);
}
printf("length is %d\n", q.len);
for (i = 0; i < q.len; i++) {
printf("%d\n", *(q.arr+i));
}
return 0;
}
I want to write 0 to 9 to a memory block which q.arr points to.
I don't want to use malloc in main(), since I don't know how many bytes I need before I call write_seq. I want to locate new memory every time when write_seq is called. Here's how output should look like.
length is 10
0
1
2
3
4
5
6
7
8
9
My implementation of write_seq() would cause core dumped. I don't know how to fix it. Thank you.
To add members to the array when you don't know in advance the size of that array, you'd need to use realloc() to increase the size on demand. However it's inefficient to do that for every change to the array size, so it would be more usual to allow for a certain amount of headroom (whether that be a fixed increment or a percentage based amount) in the buffer.
The corollary of that is you need to store the current capacity of the buffer as well as the offset to the amount currently used.
This also means that there'll be a certain amount of memory wastage, but that's the trade off you have to make.
My approach would look something like this, abstracting the operations that you might want to perform on a seq.
typedef struct {
size_t capacity;
size_t offset;
uint16_t *arr;
} seq;
static const size_t SEQ_INITIAL = 8;
static const size_t SEQ_INCREMENT = 8;
int seq_init(seq *seq) {
assert(seq != NULL); /* catch null seq */
assert(seq->arr == NULL); /* error to call on already init'd seq */
seq->capacity = SEQ_INITIAL;
seq->offset = 0;
seq->arr = malloc(seq->capacity * sizeof(seq->arr[0]));
return seq->arr == NULL ? -1 : 0;
}
static int seq_grow(seq *seq) { /* private implementation detail */
size_t new_capacity = seq->capacity + SEQ_INCREMENT;
void *p = realloc(seq->arr, new_capacity * sizeof(seq->arr[0]));
if (p == NULL) { /* realloc failed, seq unmodified */
return -1;
}
seq->arr = p;
seq->capacity = new_capacity;
return 0;
}
int seq_write(seq *seq, uint16_t value) {
assert(seq != NULL); /* catch null seq */
if ((seq->offset == seq->capacity) && seq_grow(seq) < 0) {
return -1; /* write failed */
}
assert(seq->arr != NULL); /* catch bad seq */
assert(seq->offset < seq->capacity); /* ensure seq really has room */
seq->arr[seq->offset++] = value;
return 0;
}
void seq_free(seq *seq) {
if (seq != NULL) {
free(seq->arr);
seq->arr = NULL;
}
}
You need to use realloc(), not malloc(), like this:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef struct {
int len;
int *arr;
} seq;
void write_seq(seq *q)
{
q->arr = realloc (q->arr, (q->len + 1) * sizeof(int));
q->arr[q->len] = q->len;
q->len++;
}
int main(void)
{
seq q;
q.len = 0;
q.arr = NULL;
for(int i = 0; i < 10; ++i)
write_seq(&q);
printf("length is %d\n", q.len);
for (int i = 0; i < q.len; i++) {
printf("%d\n", q.arr[i]);
}
free(q.arr);
return 0;
}
Output:
length is 10
0
1
2
3
4
5
6
7
8
9
#include <stdio.h>
#include <stdlib.h>
// Resource
typedef struct _Resource Resource;
// ResourceBuffer
typedef struct _ResourceBuffer ResourceBuffer;
ResourceBuffer *resource_buffer_new(int);
ResourceBuffer *resourceBuffer;
void resource_buffer_test();
struct _ResourceBuffer {
char *id;
int size;
Resource **buffer;
};
struct _Resource {
int id;
char *status;
};
Resource *resource_new(int i) {
Resource *r = malloc(sizeof(*r));
r->status = "groovy";
r->id = i;
return r;
}
void resource_buffer_test() {
printf("buftest has buf as %d\n",resourceBuffer->buffer);
printf("buftest has drefbuf as %d\n",*(resourceBuffer->buffer));
Resource *bp[resourceBuffer->size];
bp[0] = *(resourceBuffer->buffer+0);
bp[1] = *(resourceBuffer->buffer+1);
bp[2] = *(resourceBuffer->buffer+2);
int i = 0;
for (i = 0; i < 3; i++) {
printf("address is %d\n", bp[i]);
}
for (i = 0; i < 3; i++) {
//printf("ptrBuffer r%d is %s\n", i, (*((Resource **)(resourceBuffer->buffer)+i))->status);
printf("Buffer r%d is %s\n", bp[i]->id, bp[i]->status);
}
}
ResourceBuffer *resource_buffer_new(int bufferSize) {
ResourceBuffer *r = malloc(sizeof(*r));
Resource *b[bufferSize];
int i;
for (i = 0; i < bufferSize; i++) {
b[i] = resource_new(i);
}
for (i = 0; i < bufferSize; i++) {
printf("res address is %d\n", b[i]);
printf("pnt address is %d\n", &b[i]);
}
printf("b address is %d\n", b);
r->buffer = b;
printf("buffer set to %d\n", r->buffer);
r->size = bufferSize;
r->id = "foo";
return r;
}
int main(int argc, char** argv) {
// initialize buffer
resourceBuffer = resource_buffer_new(3);
resource_buffer_test();
return (EXIT_SUCCESS);
}
The output is:
res address is 36585520
pnt address is 783569984
res address is 36585552
pnt address is 783569992
res address is 36585584
pnt address is 783570000
b address is 783569984
buffer set to 783569984
buftest has buf as 783569984
buftest has drefbuf as 36585520
address is 36585520
address is 36585552
address is 36585520
Buffer r0 is groovy
Buffer r1 is groovy
Buffer r0 is groovy
What confuses me is the last 6 lines... Why in resource_buffer_test() do b[0] and b[2] end up pointing to the Resource struct r0?
For some reason this part fails:
bp[0] = *(resourceBuffer->buffer+0);
bp[1] = *(resourceBuffer->buffer+1);
bp[2] = *(resourceBuffer->buffer+2);
Where *(resourceBuffer->buffer+2) somehow ends up pointing back to the first element in the array, rather than the third.
Why does this happen? What causes the C pointer arithmetic to reset *(resourceBuffer->buffer+2) back to *(resourceBuffer->buffer+0)?
What is really odd (to me anyway)... is that when I change the resource_buffer_new function to look like this:
ResourceBuffer *resource_buffer_new(int bufferSize) {
ResourceBuffer *r = malloc(sizeof(*r));
Resource *b[bufferSize+1];
(note the *b[bufferSize+1]) -- then it works as expected..
Why do I need to have extra room in my buffer array for the pointer arithmetic to work?
r->buffer = b; is your problem. b is a local variable that goes out of scope once you return from resource_buffer_new(). If you made b static or allocated it, it would be ok.