Array of structs each containing dynamic arrays - c

I'm somewhat well-versed with C and I thought I had pointers all figured out until I ran into this problem. I'm creating an array-implemented stack of structs. Easy enough, but I'm running into a problem when my struct contains a dynamically allocated array.
The struct is:
typedef struct state {
int* S;
double prob;
} state_t;
Now say I'd like to create an array of 10 of those structs, each with an integer array of say 5 integers. I can allocate that array as:
state_t *newContents;
newContents = (state_t *)malloc((sizeof(state_t) + 5 * sizeof(int)) * 10);
And I can create a struct to go in the first slot:
state_t *root = malloc(sizeof *root + 5 * sizeof(int));
root->prob = 1.0;
root->S[0] = 3;
root->S[1] = 5;
root->S[2] = 7;
root->S[3] = 2;
root->S[4] = 0;
newContents[0] = *root;
But when I attempt to add a second struct, Seg fault. It's because the way the array is indexing is by the size of the struct without the int array, meaning each entry is 16 bytes long - 8 for the double + 8 for the pointer. I want it to instead index by 28 - 8 for the double and 4*5 for the ints. Does anyone know a way to access elements of this array correctly?
Thanks!

You're allocating your structs wrong. The struct itself is separate from its dynamically-allocated array and needs to be allocated separately:
// Allocate the structs.
state_t *newContents = malloc(10*sizeof(*newContents));
// Allocate the S array of the first struct.
newContents[0].S = malloc(5*sizeof(int));
newContents[0].S[0] = 3;
...
If you want a struct that actually contains an array of runtime-determined length, rather than pointing to one as your current struct does, you need a flexible array member:
struct state_t {
double prob;
int S[]; // No length specified!
};
Then you can malloc(sizeof(state_t) + n*sizeof(int)) and actually get a contiguous block of memory where the struct and its array are together. However, you can't put make an array of state_ts properly if you do this, since the compiler would have no idea where one struct ends and another begins.

Do this:
state_t *newContents;
newContents = malloc(sizeof(state_t)*10);
int i;
for (i=0;i<10;i++)
(newContents+i)->S=malloc(5 * sizeof(int));
If you want newContents to be an array of structs of size 10, then it should allocate size equal to sizeof(state_t)*10. The int *s within each struct should be allocated explicitly.

Using
Arrays of Length Zero and GCC extensions of it
proper type casting
proper pointer arithmetic
you could get what you want, more or less.
Here is my testing program (compiling with gcc -std=c99):
#include <stdio.h>
#include <stdlib.h>
typedef struct state {
double prob;
int S[];
} state_t;
int main(void) {
size_t stateSize;
state_t *newContents;
stateSize = sizeof(state_t) + 5*sizeof(int);
newContents = malloc(stateSize * 10);
for (int i = 0; i < 10; i++) {
state_t *state = (state_t *)((char *)newContents + i * stateSize);
state->prob = i;
for (int j = 0; j < 5; j++) {
state->S[j] = i * j;
}
}
for (int i = 0; i < 10; i++) {
state_t *state = (state_t *)((char *)newContents + i * stateSize);
printf("[%d] prob: %f\n", i, state->prob);
for (int j = 0; j < 5; j++) {
printf("\tS[%d]: %d\n", j, state->S[j]);
}
}
}
Run:
$ ./a.out
[0] prob: 0.000000
S[0]: 0
S[1]: 0
S[2]: 0
S[3]: 0
S[4]: 0
[1] prob: 1.000000
S[0]: 0
S[1]: 1
S[2]: 2
S[3]: 3
S[4]: 4
[2] prob: 2.000000
S[0]: 0
S[1]: 2
S[2]: 4
S[3]: 6
S[4]: 8
[3] prob: 3.000000
S[0]: 0
S[1]: 3
S[2]: 6
S[3]: 9
S[4]: 12
[4] prob: 4.000000
S[0]: 0
S[1]: 4
S[2]: 8
S[3]: 12
S[4]: 16
[5] prob: 5.000000
S[0]: 0
S[1]: 5
S[2]: 10
S[3]: 15
S[4]: 20
[6] prob: 6.000000
S[0]: 0
S[1]: 6
S[2]: 12
S[3]: 18
S[4]: 24
[7] prob: 7.000000
S[0]: 0
S[1]: 7
S[2]: 14
S[3]: 21
S[4]: 28
[8] prob: 8.000000
S[0]: 0
S[1]: 8
S[2]: 16
S[3]: 24
S[4]: 32
[9] prob: 9.000000
S[0]: 0
S[1]: 9
S[2]: 18
S[3]: 27
S[4]: 36

Related

Why 2 is not smaller than 10 on Codeblocks?

I just worked to my final exam with simple codes; when I try to sorting strings, I face annoying error. Why 2 is not smaller than 10 on my CodeBlocks IDE but is smaller than 10 on real and onlinegdb.com?
This is the annoying code:
#include <string.h>
#include <stdio.h>
#define STR_SIZ 20
int main()
{
char strArr[][STR_SIZ] = {"abc", "hdas", "sdfasf", "kakldf", "caksl", "casd", "keam", "cznjcx", "mnxzv", "jkalkds"};
char minStr[STR_SIZ];
strcpy(minStr, strArr[0]);
int N = sizeof(strArr)/sizeof(minStr);
// int N = 10;
for(int x = 0; x < N-1; x++)
{
printf("%d", x);
strcpy(minStr,strArr[x]);
int j;
for(j=1+x; j < 10; j++)
{
printf("%4d\n", j);
int cmp = strcmp(strArr[j], minStr);
if(cmp < 0)
strcpy(minStr,strArr[j]);
}
char temp[STR_SIZ];
strcpy(temp,strArr[x]);
strcpy(strArr[x], minStr);
strcpy(strArr[j], temp);
}
return 0;
}
Output on onlinegdb.com:
0 1
2
3
4
5
6
7
8
9
1 2
3
4
5
6
7
8
9
2 3
4
5
6
7
8
9
3 4
5
6
7
8
9
4 5
6
7
8
9
5 6
7
8
9
6 7
8
9
7 8
9
8 9
Output on CodeBlocks:
0 1
2
3
4
5
6
7
8
9
1 2
3
4
5
6
7
8
9
2
PS: I just have used Codeblock in the morning and it was okey with executing.
strArr has 10 elements. At the end of your loop, you call strcpy(strArr[j], temp);. This will write to strArr[10], which is out of bounds and will overwrite some unknown memory. Anything can happen after that.
You should save the j value when you copy a string into minStr.
FYI, your code above prints this as your final string order with onlinegdb:
abc
caksl
caksl
caksl
caksl
casd
cznjcx
cznjcx
jkalkds
jkalkds
So I think you have other problems as well.
try this
#include <string.h>
#include <stdio.h>
#define STR_SIZ 20
int main()
{
char strArr[][STR_SIZ] = {"abc", "hdas", "sdfasf", "kakldf", "caksl", "casd", "keam", "cznjcx", "mnxzv", "jkalkds"};
strcpy(minStr, strArr[0]);
// Calculate the number of elements this way.
const int N = sizeof(strArr)/sizeof(strArr[0]);
// int N = 10;
for(int x = 0; x < N-1; x++)
{
printf("%d", x);
int j;
for(j=1+x; j < N; j++) // Use N here too!
{
printf("%4d\n", j);
int cmp = strcmp(strArr[j], strArr[x]);
if(cmp < 0)
{
// Do the swaps only when needed.
char temp[STR_SIZ];
strcpy(temp,strArr[x]);
strcpy(strArr[x], strArr[j]);
strcpy(strArr[j], temp);
}
}
}
// Verify result
for(int x = 0; x < N; x++) printf("%s\n", strArr[x]);
return 0;
}
I moved your swap into your if check and got rid of your minStr as it was not needed. Notice how I calculate the N size too. Honestly, you were close, but you needed to verify your output.

Returning array in C: random errors, garbage values

I'm trying to get this to work but I keep getting really weird errors, sometimes it executes without error, sometimes I get memory access violation errors, 7 of the returned values are always garbage and there's a printf that the program won't work with for some reason. I'm not good with C so I haven't the slightest clue what is going on.
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
int gen_bp() {
int min = 0;
int max = 3;
int r;
r = (rand() % (max + 1 - min)) + min;
return r;
}
int * gen_gene(int len) {
int a;
int * gene = malloc(len);
int bp;
srand( (unsigned)time( NULL ) );
for( a = 0; a < len; a = a + 1 ){
bp = gen_bp();
printf("value of a: %i\n", bp); //if i remove this line, it crashes?!
gene[a] = bp;
}
return gene;
}
int main()
{
char codons[4] = {'G','T','A','C'};
int genelen = 20;
int counter;
int * gene;
gene = gen_gene(genelen);
for( counter = 0; counter < genelen; counter++ ){
printf("%i value of a: %i\n", counter, gene[counter]);
}
free(gene);
return(0);
}
This is the output I get
value of a: 1
value of a: 1
value of a: 3
value of a: 0
value of a: 2
value of a: 1
value of a: 3
value of a: 3
value of a: 1
value of a: 2
value of a: 3
value of a: 0
value of a: 3
value of a: 1
value of a: 0
value of a: 2
value of a: 3
value of a: 2
value of a: 2
value of a: 0
0 value of a: 1
1 value of a: 1
2 value of a: 3
3 value of a: 0
4 value of a: 2
5 value of a: 1
6 value of a: 3
7 value of a: 3
8 value of a: 1
9 value of a: 2
10 value of a: 1635131449 // 10 to 16 are always garbage, and never change
11 value of a: 1702194273
12 value of a: 543584032
13 value of a: 891304545
14 value of a: 808661305
15 value of a: 892351281
16 value of a: 2570
17 value of a: 2
18 value of a: 2
19 value of a: 0
Sometimes it ends fine with 0 error, other times it crashes after the output. Absolutely not the slightest clue why.
You are reserving space for len bytes, but you want to reserve space for
int * gene = malloc(sizeof(int) * len);
or
int * gene = malloc(sizeof(*gene) * len);
And you forget to #include <time.h>
Using malloc directly is too error-prone; in your code you forgot to multiply with the element size.
Use a macro instead:
#define NEW_ARRAY(ptr, n) (ptr) = malloc((n) * sizeof (ptr)[0])
int *gene;
NEW_ARRAY(gene, len);

Process data from char array

I have a little problem,
I have a char array like this:
char buff[256] = { "2 22 3 14 5 8 23 45 2 7 88"};
and what I need to do is:
if 1st number in buff is bigger than 5 I need to sort this numbers ASC
if 1st number in buff is smaller than 5 I need to sort this numbers DESC
in this example the 1st number is 2, so I need to sort this array DESC
I want to create an int array and copy numbers from char buff to int array but I can't figure out how to do this.
Sorting this data in int array will be easy.
I have tried smth like this:
int array[256];
for (int i = 0; i<26; i++)
array[i] = atoi(&buff2[i]);
and the result is not good
array[0]: 2
array[1]: 22
array[2]: 22
array[3]: 2
array[4]: 3
array[5]: 3
array[6]: 14
array[7]: 14
array[8]: 4
array[9]: 5
array[10]: 5
array[11]: 8
array[12]: 8
array[13]: 23
array[14]: 23
array[15]: 3
array[16]: 45
array[17]: 45
array[18]: 5
array[19]: 2
array[20]: 2
array[21]: 7
array[22]: 7
array[23]: 88
array[24]: 88
array[25]: 8
For a 'C' answer, I would use strtol, because it tells you where the parsed number ends in the buffer:
#include <stdio.h>
#include <stdlib.h>
int main() {
char buff[] = "2 22 3 14 5 8 23 45 2 7 88";
char* p=buff;
for(;;) {
char* ep; // end pointer
int n = strtol(p, &ep, 0);
// if ep == p, no parsing took place
if(p != ep) {
// parsing succeeded
printf("%d\n", n);
}
if(!*ep) break; // check if we hit the end of the string
p = ep + 1; // advance to the next character
}
}
Prints:
2
22
3
14
5
8
23
45
2
7
88
For C++, you may want to convert the text to a std::istringstream then treat as an input stream:
const char buff[] = { "2 22 3 14 5 8 23 45 2 7 88"};
const std::string text(buff);
std::vector<int> database;
std::istringstream buf_stream(text);
int value;
while (buf_stream >> value)
{
database.push_back(value);
}
For ascending and descending sorting, you can write comparison functions and pass them to std::sort.

Implementation of Dynamic Table in C

Consider a dynamic table with the following properties:
Elements are stored in a dynamic array
Capacity is the size of the dynamic array
Size is defined is the number of elements stored in the array
Insert elements into this dynamic table. Double capacity if size is equal to capacity before push_back()
Don't use malloc or calloc functions.
Input: (n, elements)
9
6 7 8 12 4 10 11 1 15
Output:
capacity = 1; size = 1; elements = 6
capacity = 2; size = 2; elements = 6 7
capacity = 4; size = 3; elements = 6 7 8
capacity = 4; size = 4; elements = 6 7 8 12
capacity = 8; size = 5; elements = 6 7 8 12 4
capacity = 8; size = 6; elements = 6 7 8 12 4 10
capacity = 8; size = 7; elements = 6 7 8 12 4 10 11
capacity = 8; size = 8; elements = 6 7 8 12 4 10 11 1
capacity = 16; size = 9; elements = 6 7 8 12 4 10 11 1 15
#include <stdio.h>
int size=0;
int capacity=0;
int * double_capacity(int *a) {
int l=0;
if(capacity==0) capacity++;
capacity=capacity*2;
int b[capacity];
for(l;l<size;l++){
//printf("%d : %d \n",l,a[l]);
b[l]=a[l];
}
return b;
}
int * push_back(int *a,int j) {
if(size==capacity)
a=double_capacity(a);
a[size]=j;
size++;
int k=0;
printf("capacity = %d; size = %d; elements = ",capacity,size);
for(k=0;k<size;k++) {
printf(" %d",*(a+k));
}
printf("\n");
return a;
}
main() {
int *a;
int n,i,j,k,l;
scanf("%d",&n);
int temp[n];
for(i=0; i<n; i++) {
scanf("%d",&temp[i]);
}
for(i=0; i<n; i++) {
a=push_back(a,temp[i]);
}
}
it is showing compile error like
\temp.c: In function ‘double_capacity’:
temp.c:16:2: warning: function returns address of local variable [-Wreturn-local-addr]
return b;
^
even though i run this
when i gave input
3 3 2 1
output
capacity = 1; size = 1; elements = 3
capacity = 2; size = 2; elements = 3 2
capacity = 4; size = 3; elements = 3 2 1
when i gave input
5 5 4 3 2 1
output
capacity = 1; size = 1; elements = 5
capacity = 2; size = 2; elements = 5 4
capacity = 4; size = 3; elements = 5 4 3
capacity = 4; size = 4; elements = 0 0 -2128976676 2
capacity = 8; size = 5; elements = 0 0 -2128976676 32524 1
This won't work the way you want it to:
int * double_capacity(int *a)
{
int l=0;
if(capacity==0)
capacity++;
capacity=capacity*2;
int b[capacity];
for(l;l<size;l++)
{
//printf("%d : %d \n",l,a[l]);
b[l]=a[l];
}
return b;
}
The array b only exists for the lifetime of the double_capacity function; once the function exits, b no longer exists, and any pointer to it is now invalid.
You can't use VLAs this way.
I notice your instructions said nothing about the realloc function...
EDIT
If you cannot use any of the standard memory management functions (malloc, calloc, or realloc), then the only real alternative I can think of is to create your own memory pool and allocate your table elements from it.
Basically, you'd declare a large array of unsigned char at file scope like so:
#define HEAP_SIZE 8192 // 8 KB heap, use whatever size you need
static unsigned char heap[HEAP_SIZE];
then you'd grab chunks of this array to build your table. You'll need to do some bookkeeping to manage available and allocated blocks, their addresses and sizes within that array, etc. If you know what you're doing, this is a day or so of solid effort depending on how robust you want it to be.
Then again, there may be something a little more straightforward that I'm forgetting about. I just can't think of it at the moment.

Output of array program

#include<stdio.h>
int main() {
int arr[10] = { 11 , [9] = 22 };
int i;
arr[13] = 2452;
arr[10] = 1212;
for(i = 0; i < 15; i++) {
printf("arr[%i] %i\n " , i, arr[i]);
}
return 0;
}
The output it is generating as follows:
arr[0] 11
arr[1] 0
arr[2] 0
arr[3] 0
arr[4] 0
arr[5] 0
arr[6] 0
arr[7] 0
arr[8] 0
arr[9] 22
arr[10] 10
arr[11] -1216806924
arr[12] 0
arr[13] 2452
arr[14] -1218431789
output of arr [10] and arr [13] I'm unable to understand.
arr[] size is 10, so arr[0] to [9] values are valid. everything else is rubish, you are accesing memory out of bounds
I will try to explain. It seems that the compiler placed local variables in the stack in the following way as they were declared
int arr[10] = { 11 , [9] = 22 };
int i;
In this case object int i occupies memory that corresponds to arr + 10 (actual elements of the array occupy memory from arr + 0 to arr + 9 inclusively)
Thus when in the loop you output arr[10] then in fact you output object i that in this moment is equal naturally to 10.
That is at first you set i to 1212 (arr[10] = 1212;) and then in the loop the variable is overwritten i and arr[10[ share the same memory.
As for arr[13] then the program outputs its value as it was set before the loop.
Of course your program has undefined behaviour because you are overwritting memory beyond the array.

Resources