I got this chunk of code I can't really comprehend.
I got stuck after it replaced pow2s's g to a map's gen structure. And from there, I can't see how it continues tracking the value, and how it is stored.
The code compiles and runs.
Can someone help me understand this code? Thanks!
PS: I'm learning C
It is translated from the follow Python code:
>>> def pow2s():
yield 1
for i in map((lambda x:2*x),pow2s()):
yield i
>>> def mymap(f,iter):
for i in iter:
yield f(i)
And the translated C code:
#include <stdio.h>
#include <stdlib.h>
struct gen { // generic structure, the base of all generators
int (*next)() ;
int continue_from ;
} ;
typedef int (*fptr)() ;
// Each iterator has 3 components: a structure, a constructor for the structure,
// and a next function
// map
struct mapgen { // structure for map
int (*next)() ;
int continue_from ; // not really required, provided for compatibility
fptr f ;
struct gen *g ;
} ;
int map_next(struct mapgen *p) { // next function for map
return p->f(p->g->next(p->g)) ;
}
struct gen *map(fptr f, struct gen *g) { // constructor for map iterator
struct mapgen *p = (struct mapgen *)malloc(sizeof(struct mapgen));
p->next = map_next;
p->continue_from = 0;
p->f = f;
p->g = g;
return (struct gen *)p ;
}
// powers of 2
struct pow2s { // structure
int (*next)() ;
int continue_from ;
struct gen *g ;
};
int times2(int x) { // anonymous lambda is translated into this
return 2*x ;
}
struct gen *pow2() ; // forward declaration of constructor
int pow2next(struct pow2s * p){ // next function for iterator
switch(p->continue_from) {
case 0:
p->continue_from = 1;
return 1;
case 1:
p->g = map(times2,pow2()) ;
p->continue_from = 2;
return p->g->next(p->g) ;
case 2:
p->continue_from = 2;
return p->g->next(p->g) ;
}
}
struct gen * pow2() { // constructor for pow2
struct pow2s * p = (struct pow2s *)malloc(sizeof(struct pow2s));
p->next = pow2next;
p->continue_from = 0;
return (struct gen *)p;
}
// in main, create an iterator and print some of its elements.
int main() {
int i ;
struct gen * p = pow2() ;
for(i=0;i<10;i++)
printf("%d ",p->next(p)) ;
printf("\n");
}
The code shows how you can generate an arbitrary sequence of numbers
by means of 'generators'.
generators are a popular tool in dynamic languages like python and enable one to
iterate over an arbitrary long sequence without allocating the whole sequence at once.
The tracking happens in the lines
p->next = pow2next;
p->continue_from = 0;
Which tells p that it should call pow2next to obtain the next item in the sequence
and continue_from = 0 to indicate that where at the start of the sequence.
When you call p->next(p) it will in fact just call pow2next with p as it's parameter.
For the first call this will simply return 1 and increment continue_from to 2.
switch(p->continue_from) {
case 0:
p->continue_from = 1;
return 1;
/* ... */
On the second call (continue_from = 2) it will create a new map_gen structure working
on a fresh struct pow2s and using the function times2:
case 1:
p->g = map(times2,pow2()) ;
p->continue_from = 2;
return p->g->next(p->g) ;
/* ... */
All further calls go through p->g->next(p->g) which uses times2 and map_gen to retrieve the next
value / create new map_gen structures as needed.
All value tracking is done using the struct-member continue_from or by using return codes.
While showing an interesting approach to generators in C I have to state that this code leaks memory!
As you can see it allocates new structures using malloc but it never free's them.
I hope this explanation is not to confusing even if you're just starting to learn C.
If you really want to understand generators you may like to have a little python ex-course ;)
UPDATE
As you stated in your comment none of the generators ever seems to return a value > 2.
The key to the increasing numbers lies in the function map_next:
int map_next(struct mapgen *p) {
return p->f(p->g->next(p->g));
}
What this does is, instead of returning a fix, number it applies p->f()
(in our case the function times2() to the result of p->g->next(p->g).
This is a recursive call.
It will continue to call map_next() on each map_gen in the list until it reaches the last one.
This last element will return a fix value (either 1 or 2).
Which is then passed back to the previous call which will apply times2() on it and return the result to it's caller, which in turn will apply times2() on it and return the result to it's caller.... (you get the idea).
All these recursive calls sum up and form the final value.
If you print out the result of each pow2next() call you will get this:
/* first call */
1
pow2next: returning 1
pow2next: returning 2 /* times2(1) */
2
pow2next: returning 1
pow2next: returning 2 /* times2(1) */
pow2next: returning 4 /* times2(2) */
4
pow2next: returning 1
pow2next: returning 2 /* times2(1) */
pow2next: returning 4 /* times2(2) */
pow2next: returning 8 /* times2(4) */
8
pow2next: returning 1
pow2next: returning 2 /* times2(1) */
pow2next: returning 4 /* times2(2) */
pow2next: returning 8 /* times2(4) */
pow2next: returning 16 /* times2(8) */
16
/* and so on */
You can see clearly how the result of the top most call is passed all the way back to the first call to form the result.
It tracks the value by growing a tail of struct mapgen instances mixed with times2 instances
Each call to pow2next adds another pair to the tail.
The only value of this example is as an illustration of how much high level languages do for us, and how naive implementation of high-level concepts can kill your performance.
Related
I know there are lots of questions here about functions that take a variable number of arguments. I also know there's lots of docs about stdarg.h and its macros. And I also know how printf-like functions take a variable number of arguments. I already tried each of those alternatives and they didn't help me. So, please, keep that in mind before marking this question as duplicate.
I'm working on the process management features of a little embedded operating system and I'm stuck on the design of a function that can create processes that run a function with a variable number of parameters. Here's a simplified version of how I want my API to looks like:
// create a new process
// * function is a pointer to the routine the process will run
// * nargs is the number of arguments the routine takes
void create(void* function, uint8_t nargs, ...);
void f1();
void f2(int i);
void f3(float f, int i, const char* str);
int main()
{
create(f1, 0);
create(f2, 1, 9);
create(f3, 3, 3.14f, 9, "string");
return 0;
}
And here is a pseudocode for the relevant part of the implementation of system call create:
void create(void* function, uint8_t nargs, ...)
{
process_stack = create_stack();
first_arg = &nargs + 1;
copy_args_list_to_process_stack(process_stack, first_arg);
}
Of course I'll need to know the calling convention in order to be able to copy from create's activation record to the new process stack, but that's not the problem. The problem is how many bytes do I need to copy. Even though I know how many arguments I need to copy, I don't know how much space each of those arguments occupy. So I don't know when to stop copying.
The Xinu Operating System does something very similar to what I want to do, but I tried hard to understand the code and didn't succeed. I'll transcript a very simplified version of the Xinu's create function here. Maybe someone understand and help me.
pid32 create(void* procaddr, uint32 ssize, pri16 priority, char *name, int32 nargs, ...)
{
int32 i;
uint32 *a; /* points to list of args */
uint32 *saddr; /* stack address */
saddr = (uint32 *)getstk(ssize); // return a pointer to the new process's stack
*saddr = STACKMAGIC; // STACKMAGIC is just a marker to detect stack overflow
// this is the cryptic part
/* push arguments */
a = (uint32 *)(&nargs + 1); /* start of args */
a += nargs -1; /* last argument */
for ( ; nargs > 4 ; nargs--) /* machine dependent; copy args */
*--saddr = *a--; /* onto created process's stack */
*--saddr = (long)procaddr;
for(i = 11; i >= 4; i--)
*--saddr = 0;
for(i = 4; i > 0; i--) {
if(i <= nargs)
*--saddr = *a--;
else
*--saddr = 0;
}
}
I got stuck on this line: a += nargs -1;. This should move the pointer a 4*(nargs - 1) ahead in memory, right? What if an argument's size is not 4 bytes? But that is just the first question. I also didn't understand the next lines of the code.
If you are writing an operating system, you also define the calling convention(s) right? Settle for argument sizes of sizeof(void*) and pad as necessary.
I have been using C in more and more projects recently and almost ended up creating my own "object implementation" with structure pointers. However, I was curious on the speed difference between a purely functional style (with structs) and structures that call on function pointers in a more modern day object orientated style.
I have created a sample program and am unsure why the difference in timing is so large.
The program uses two timers and records the time taken to complete each task (one after the other). This does not include memory allocation/de-allocation, and both techniques are setup in a similar way (each structure has three integers as pointers of the struct).
The code itself just adds three numbers together repeatedly in a for loop for the duration specified in the macro LOOP_LEN.
Please note I have the functions being measured both inlined and the compiler optimisation was varied from none to Full Optimization (/Ox) (I am running this in Visual Studio as a pure .c file).
Object style Code
// MAGIC object
typedef struct {
// Properties
int* x;
int* y;
int* z;
// Methods
void(*init)(struct magic* self, int x, int y, int z);
int(*sum)(struct magic* self);
}magic;
// Variable init function
void* init(magic* self, int x, int y, int z) {
// Assign variables to properties
*self->x = x;
*self->y = y;
*self->z = y;
return;
}
// Add all variables together
inline int sum(magic* self) {
return ((*self->x) + (*self->y) + (*self->z));
}
// Magic object constructor
magic* new_m(int x, int y, int z) {
// Allocate self
magic* self = malloc(sizeof(magic));
// Allocate member pointers
self->x = malloc(sizeof(int));
self->y = malloc(sizeof(int));
self->z = malloc(sizeof(int));
// Allocate method pointers
self->init = init;
self->sum = sum;
// Return instance
return self;
}
// Destructor
void delete_m(magic* self) {
// Deallocate memory from constructor
free(self->x); self->x = NULL;
free(self->y); self->y = NULL;
free(self->z); self->z = NULL;
free(self); self = NULL;
return;
}
Functional (traditional) style code
// None object oriented approach
typedef struct {
int* x;
int* y;
int* z;
}str_magic;
// Magic struct constructor
str_magic* new_m_str(int x, int y, int z) {
// Allocate self
str_magic* self = malloc(sizeof(str_magic));
// Allocate member pointers
self->x = malloc(sizeof(int));
self->y = malloc(sizeof(int));
self->z = malloc(sizeof(int));
// Return instance
return self;
}
// Destructor
void delete_m_str(str_magic* self) {
// Deallocate memory from constructor
free(self->x); self->x = NULL;
free(self->y); self->y = NULL;
free(self->z); self->z = NULL;
free(self); self = NULL;
return;
}
// Sum using normal structure type
inline int sum_str(str_magic* self) {
return ((*self->x) + (*self->y) + (*self->z));
}
Timer test and main program entry point
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define LOOP_LEN 1000000000
// Main entry point
int main(void) {
// Start timer for first task
clock_t start1, end1, start2, end2;
double cpu_time_used1, cpu_time_used2;
// Init instances before timer
magic* object1 = new_m(1, 2, 3);
// Start task1 clock
start1 = clock();
for (int i = 0; i < LOOP_LEN; i++) {
// Perform method sum and store result
int result1 = object1->sum(object1);
}
// Stop task1 clock
end1 = clock();
// Remove from memory
delete_m(object1);
// Calculate task1 execution time
cpu_time_used1 = ((double)(end1 - start1)) / CLOCKS_PER_SEC;
// Init instances before timer
str_magic* object2 = new_m_str(1, 2, 3);
// Start task2 clock
start2 = clock();
for (int i = 0; i < LOOP_LEN; i++) {
// Perform function and store result
int result2 = sum_str(object2);
}
// Stop task2 clock
end2 = clock();
// Remove from memory
delete_m_str(object2);
// Calculate task 2 execution time
cpu_time_used2 = ((double)(end2 - start2)) / CLOCKS_PER_SEC;
// Print time results
printf("----------------------\n Task 1 : %.*e\n----------------------\n Task 2 : %.*e\n----------------------\n", cpu_time_used1, cpu_time_used2);
if (cpu_time_used1 < cpu_time_used2) {
printf("Object Oriented Approach was faster by %.*e\n", cpu_time_used2-cpu_time_used1);
}
else {
printf("Functional Oriented Approach was faster by %.*e\n", cpu_time_used1 - cpu_time_used2);
}
// Wait for keyboard interrupt
getchar();
return 0;
}
Every single time the program is ran, the functional programming always performed faster. The only reason I could think is that it has to access an extra layer of pointer through the structure to call the method, but I would have thought inline would reduce this delay.
Although the delay gets smaller as the optimization is increased, I would be curious to know why it is so much different at levels of low/no optimization and is this therefore considered a valid programming style?
Your 2nd loop with /O2 loop is compiled into:
call clock
mov edi, eax ; this is used later to calculate time
call clock
E.g. there is no code at all. Compiler is able to understand that result of sum_str function is unused, so it removes it completely. Compiler is not able to do the same for the first case.
So there is no real comparison when optimization is enabled.
Without optimizations there are just more code to execute.
First loop is compiled to:
cmp DWORD PTR i$1[rsp], 1000000000
jge SHORT $LN3#main ; loop exit
mov rcx, QWORD PTR object1$[rsp]
mov rax, QWORD PTR object1$[rsp] ; extra instruction
call QWORD PTR [rax+32] ; indirect call
mov DWORD PTR result1$3[rsp], eax
jmp SHORT $LN2#main ; jump to the next iteration
Second loop:
cmp DWORD PTR i$2[rsp], 1000000000
jge SHORT $LN6#main ; loop exit
mov rcx, QWORD PTR object2$[rsp]
call sum_str
mov DWORD PTR result2$4[rsp], eax
jmp SHORT $LN5#main ; jump to the next iteration
With both sum and sum_str being compiled to equivalent sequences of instructions.
The difference is in one instruction in loop, plus indirect calls are slower. Overall there shouldn't be a huge difference between two versions without optimizations - both should be slow.
I think Ivan and you have already provided the answer. I just want to add about inline function. Even though you declare a function as inline it not necessary that compiler will always consider it as inline. Based on complexity compiler might consider it as normal function.
As you said, the former case has additional indirection of pointer reference. Though you declare sum as a inline function, as sum function pointer is put into object member, it cannot be inlined easily.
I suggest you compare generated assembly code with -O0 ~ -O3.
I work in R using C libraries. I need to pass to a C function an array with numbers between 1 and 10 but that could also be "NA". Then in C, depending on the value I need to set the output.
Here's a simplified code
heredyn.load("ranking.so")
fun <- function(ranking) {
nrak <- length(ranking)
out <- .C("ranking", as.integer(nrak), as.character(ranking), rr = as.integer(vector("integer",nrak)))
out$rr
}
ranking <- sample(c(NA,seq(1,10)),10,replace=TRUE)
rr <- fun(ranking)
The C function could simply be such as
#include <R.h>
void ranking(int *nrak, char *ranking, int *rr) {
int i ;
for (i=0;i<*nrak;i++) {
if (ranking[i] == 'NA')
rr[i] = 1 ;
else
rr[i] = (int) strtol(&ranking[i],(char **)NULL,10) ;
}
}
Due to the "NA" value I set ranking as character but maybe there's another way to do that, using integer and without replacing "NA" to 0 before calling the function?
(The code like this, gives me always an array of zeros...)
Test for whether the value is an NA using R_NaInt, like
#include <R.h>
void ranking_c(int *nrak, int *ranking, int *rr) {
for (int i=0; i < *nrak; i++)
rr[i] = R_NaInt == ranking[i] ? -1 : ranking[i];
}
Invoke from R by explicitly allowing NAs
> x = c(1:2, NA_integer_)
> .C("ranking_c", length(x), as.integer(x), integer(length(x)), NAOK=TRUE)[[3]]
[1] 1 2 -1
Alternatively, use R's .Call() interface. Each R object is represented as an S-expression. There are C-level functions to manipulate S-expressions, e.g., length Rf_length(), data access INTEGER(), and allocation Rf_allocVector() of different types of S-expressions such as INTSXP for integer vectors.
R memory management uses a garbage collector that can run on any call that allocates memory. It is therefore best practice to PROTECT() any R allocation while in scope.
Your function will accept 0 or more S-expressions as input, and return a single S-expression; it might be implemented as
#include <Rinternals.h>
#include <R_ext/Arith.h>
SEXP ranking_call(SEXP ranking)
{
/* allocate space for result, PROTECTing from garbage collection */
SEXP result = PROTECT(Rf_allocVector(INTSXP, Rf_length(ranking)));
/* assign result */
for (int i = 0; i < Rf_length(ranking); ++i)
INTEGER(result)[i] =
R_NaInt == INTEGER(ranking)[i] ? -1 : INTEGER(ranking)[i];
UNPROTECT(1); /* no more need to protect */
return result;
}
And invoked from R with .Call("ranking_call", as.integer(ranking)).
Using .Call is more efficient than .C in terms of speed and memory allocation (.C may copy atomic vectors on the way in), but the primary reason to use it is for the flexibility it offers in terms of working directly with R's data structures. This is especially important when the return values are more complicated than atomic vectors.
You are attempting to address a couple of delicate and non-trivial points, least of all how to compile code with R, and to test for non-finite values.
You asked for help with C. I would like to suggest C++ -- which you do not need to use in a complicated way. Consider this short file with contains a function to process a vector along the lines you suggest (I just test for NA and then assign 42 as a marker for simplicit) or else square the value:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector foo(NumericVector x) {
unsigned int n = x.size();
for (unsigned int i=0; i<n; i++)
if (NumericVector::is_na(x[i]))
x[i] = 42.0;
else
x[i] = pow(x[i], 2);
return x;
}
/*** R
foo( c(1, 3, NA, NaN, 6) )
*/
If I save this on my box as /tmp/foo.cpp, in order compile, link, load and even run the embedded R use example, I only need one line to call sourceCpp():
R> Rcpp::sourceCpp("/tmp/foo.cpp")
R> foo( c(1, 3, NA, NaN, 6))
[1] 1 9 42 42 36
R>
We can do the same with integers:
// [[Rcpp::export]]
IntegerVector bar(IntegerVector x) {
unsigned int n = x.size();
for (unsigned int i=0; i<n; i++)
if (IntegerVector::is_na(x[i]))
x[i] = 42;
else
x[i] = pow(x[i], 2);
return x;
}
I have a routine calling gSoap API function soap_malloc. But the program gives me a segmentation fault whenever I try to access the memory allocated by soap_malloc. When I use gdb to debug it. I find that inside soap_malloc, return value stored in register %rax is 0x7fffec0018f0. But on return, %rax changed to 0xffffffffec0018f0. Only the lower 32-bit was retained, the higher 32-bit all changed to 1. And that lead to accessing an address which is quite high, therefore caused the routine stopped. Thanks for you all to give me any ideas on how can this be happening. I'm running my multi-thread program in Ubuntu12.04 x86-64.
This is how I call it:
void *temp = soap_malloc(soap, 96);
And this is the soap_malloc implementation(only that else part is executed, and macro SOAP_MALLOC is just passing the second argument to malloc, SOAP_CANARY is constant 0xC0DE):
#ifndef SOAP_MALLOC /* use libc malloc */
# define SOAP_MALLOC(soap, size) malloc(size)
#endif
#ifndef SOAP_CANARY
# define SOAP_CANARY (0xC0DE)
#endif
void* soap_malloc(struct soap *soap, size_t n)
{ register char *p;
if (!n)
return (void*)SOAP_NON_NULL;
if (!soap)
return SOAP_MALLOC(soap, n);
if (soap->fmalloc)
p = (char*)soap->fmalloc(soap, n);
else
{ n += sizeof(short);
n += (-(long)n) & (sizeof(void*)-1); /* align at 4-, 8- or 16-byte boundary */
if (!(p = (char*)SOAP_MALLOC(soap, n + sizeof(void*) + sizeof(size_t))))
{ soap->error = SOAP_EOM;
return NULL;
}
/* set the canary to detect corruption */
*(unsigned short*)(p + n - sizeof(unsigned short)) = (unsigned short)SOAP_CANARY;
/* keep chain of alloced cells for destruction */
*(void**)(p + n) = soap->alist;
*(size_t*)(p + n + sizeof(void*)) = n;
soap->alist = p + n;
}
soap->alloced = 1;
return p;
}
This is the definition of SOAP_NON_NULL:
static const char soap_padding[4] = "\0\0\0";
#define SOAP_NON_NULL (soap_padding)
Updates(2013-03-12)
I explicitly declared soap_malloc as returning void * and the problem solved. Previously, the returned value is truncated to int and the sign bit 1 was extended when assigning the result to void *temp.
Does the calling code have a proper prototype for the soap_malloc() function in scope?
It seems the void * is being converted to int, i.e. the default return type. This happens if the function hasn't been properly declared.
I am attempting to tackle college worksheet on C programming (no marking for it, just to improve our learning). What we're meant to do is get a few details about shipping docks. I decided to use structures for this.
My code is below, what I need help with is to print out the information (to see if its working) of whats at the location of the shipyards .run.
Everything compiles and according to the debugger shipyard1.run and shipyard2.run point to different locations, but I can not see the values.
int main(int argc, char** argv)
{
typedef struct dockInfo
{
int dockCode;
int dockLength;
}dckDetails;
typdef struct shipyard
{
char dockName[20];
/* however big this number is thats how many dockInfo structs are needed.*/
int numOfDocks;
dckDetails *run; //points to the array of dockInfo structs
};
struct dockInfo *arrayD; // the array to hold all the dockInfo structs
struct dockInfo tempo; // the temporary dockInfo struct to take in the details
struct shipyard shipyard1;
struct shipyard shipyard2;
/**
* the variables for shipyard1 and shipyard2 are then assigned
**/
int i;
for (i=0;i<shipyard1.numOfDocks;i++)
{
arrayD=calloc(shipyard1.numOfDocks,100); // allocate a new bit of memory for arrayD
tempo.dockCode=45*i;
tempo.dockLength=668*i;
arrayD[i]=tempo; //the element of arrayD becomes tempo.
}
shipyard1.run=arrayD; //make shipyard1.run point to the location of arrayD.
for (i=0;i<shipyard2.numOfDocks;i++)
{
arrayD=calloc(shipyard2.numOfDocks,100); // allocate a new bit of memory for arrayD
tempo.dockCode=1234*i;
tempo.dockLength=1200*i;
arrayD[i]=tempo; //the element of arrayD becomes tempo.
}
shipyard2.run=arrayD; //make shipyard2.run point to the new location of arrayD.
int elementTest1; // need element1test to be shipyard1.run[0].dockLength;
int elementTest2; // need element2test to be shipyard2.run[1].dockCode;
return (EXIT_SUCCESS);
}
It should be noted that I have left a lot of code out because I have yet to write it. I have used static examples for the moment (shipyard1 and shipyard2) but in the future I am going to implment a 'load info from file' feature.
Any help would be greatly appreciated and please excuse my English if it's poor, English is not my first language.
You have calloc() inside a for loop twice. Both times you're losing the address returned.
for () {
addr = calloc();
addr[i] = ...
}
the second time through the loop, the addr you got on the first time is gone (you got yourself a memory leak), the value you saved there is gone too.
Move the calloc() outside the loop ... and remember to free() the memory when you no longer need it
addr = calloc();
for () {
addr[i] = ...
}
free(addr);
Some feedback:
The memory allocation parts with calloc should occur outside the loop. Now you allocate it, and then loose track of it in the next iteration because new memory is allocated and assigned.
memory you allocate should be freed somewhere with free
shipyard1.numOfDocks (same for shipyard2) is unitialized when you use it, it may be a random number (which means you have an undefined number of loop iterations, and allocate an undefined amount of memory).
Good luck!
Others have made some very good points, and you should fix your code according to them. So far, no one seems to have seen that the call to calloc() is wrong. Instead of:
arrayD=calloc(shipyard1.numOfDocks,100);
it should be:
arrayD = calloc(shipyard1.numOfDocks, sizeof *arrayD);
You want shipyard1.numOfDocks objects, each of size equal to sizeof *arrayD.
In fact, as mentioned below, you don't need to set the memory allocated to all-zeros, so you can replace calloc() by malloc():
arrayD = malloc(shipyard1.numOfDocks * sizeof *arrayD);
(Be sure to #include <stdlib.h>, whether you call calloc() or malloc().)
I have some minor comments about style:
you don't need the typedef. You can write struct dockInfo instead of dckDetails. If you do keep the typedef, you should be consistent, and use the typedef name everywhere. You use struct dockInfo most of the time, and then use dckDetails once. Your usage suggests that you probably weren't comfortable declaring a pointer to the struct. However, struct dockInfo *run is a completely valid declaration.
you don't need the tempo object. You can instead do: arrayD[i].dockCode = 45*i; arrayD[i].dockLength = 668*i;
Unless you're running C99, you can't declare variables after statements in a block. So you should move the declarations for elementTest1 and elementTest2 to the top of main(), with other declarations.
return is a statement, not a function, so the parentheses are not needed.
Since you overwrite the memory allocated immediately, and don't need it to be zero, you can replace calloc() call by a suitable call to malloc().
As I said, these are minor comments. Your main problems lie with the wrong use of calloc, etc.
I shortened the variable names and re-wrote this to do what I think you are interested in. I also added display of the addresses the data is stored in.
Generally, when I try to understand something in the arrays and pointers world, I make the simple case work - an embedded array (my yard1) and then do the pointer thing after that (yard2, yard3)
You'll note each set of data has different start points, two add i for each point, one multiplies by i for each point.
#include <libc.h>
#include <stdlib.h>
#include <stdio.h>
#define MAX_DOCKS 100
int main(int argc, char** argv)
{
struct dock
{
int code;
int length;
};
struct yard
{
char name[20];
int numDocks;
struct dock arDocks[MAX_DOCKS]; //an array of dock structs
};
struct yard_2
{
char name[20];
int numDocks;
struct dock *run; //points to the array of dock structs
};
/* data within main function */
struct dock *arrayD; // pointer to dock structs
struct yard yard1;
struct yard_2 yard2;
struct yard_2 yard3;
int i;
char temp[] = "2 draY";
strcpy( yard2.name, temp ); /* temp is only persistant in main... */
strcpy( yard1.name, "Yard 1");
strcpy( yard3.name, "3 y 3 a 3 r 3 d 3");
yard1.numDocks = MAX_DOCKS; /* or so I guess.. */
yard2.numDocks = MAX_DOCKS; /* or so I guess.. */
yard3.numDocks = MAX_DOCKS; /* or so I guess.. */
/* get some memory, init it to 0 */
arrayD = calloc( yard2.numDocks, sizeof( struct dock ) );
/* connect to the yard2 struct via "run", a pointer to struct dock */
yard2.run = arrayD;
/* without middleman... get more memory, init it to 0 */
yard3.run = calloc( yard3.numDocks, sizeof( struct dock ) );
/* at this point arrayD could be re-used to get another hunk.. */
/* fill in and display data .. */
for (i=0;i<yard1.numDocks;i++)
{
/* This sets all the memory for yard 1... */
yard1.arDocks[i].code = 45 + i;
yard1.arDocks[i].length = 668 + i;
/* so here are some ways to display the data */
printf("%d, %d %x %d %x - ",
i, yard1.arDocks[i].code, &(yard1.arDocks[i].code),
(yard1.arDocks[i].length), &(yard1.arDocks[i].length) );
/* This sets the memory for yard 2... */
yard2.run[i].code = 45 * i;
yard2.run[i].length = 668 * i;
/* Display through a pointer to a calloc'ed array of structs is the
same syntax as the embedded array of structs. The addresses of the
array are completely different - 0xbffff704 vs 0x800000 on my Intel-based iMac... */
printf("%d %x %d %x - ",
yard2.run[i].code, &(yard2.run[i].code),
yard2.run[i].length, &(yard2.run[i].length) );
yard3.run[i].code = 100 + i;
yard3.run[i].length = 2000 + i;
/* see where second calloc got its memory... */
printf("%d %x %d %x\n",
yard3.run[i].code, &(yard3.run[i].code),
yard3.run[i].length, &(yard3.run[i].length) );
}
/* data all filled in, more demos of how to get it back: */
printf( "%s, : 1\n", yard1.name );
printf( "%d, : numOfDocs \n", yard1.numDocks );
printf( "0x%x, : arDocks \n", yard1.arDocks );
int elementTest1 = yard1.arDocks[0].length;
int elementTest2 = yard1.arDocks[1].code;
int elementTest3 = yard2.run[0].length;
int elementTest4 = yard3.run[1].code;
printf( "elementTest1: yard1.arDocks[0].length %d\n", elementTest1 );
printf( "elementTest2: yard1.arDocks[1].code %d\n", elementTest2 );
printf( "elementTest3: yard2.run[0].length %d\n", elementTest3 );
printf( "elementTest4: yard3.run[1].code; %d\n", elementTest4 );
for (i=0; i< yard2.numDocks; i++ ) {
printf("%d %d %d _ ", i, yard2.run[i].length, yard2.run[i].code);
printf(" %d %d \n", yard3.run[i].length, yard3.run[i].code);
}
return (EXIT_SUCCESS);
}
Here's an edited example of the output, compile/build via cc, cmd line a.out:
Macintosh-6:interview Bill4$ cc
dockyard.c Macintosh-6:interview
Bill4$ a.out
0 45 bffff6f8 668 bffff6fc - 0 800000 0 800004 - 100 800400 2000 800404
1 46 bffff700 669 bffff704 - 45 800008 668 80000c - 101 800408 2001 80040c
2 47 bffff708 670 bffff70c - 90 800010 1336 800014 - 102 800410 2002 800414
:
Yard 1, : 1
100, : numOfDocs
0xbffff6f8, : arDocks
elementTest1: yard1.arDocks[0].length 668
elementTest2: yard1.arDocks[1].code 46
elementTest3: yard2.run[0].length 0
elementTest4: yard3.run[1].code; 101
0 0 0 _ 2000 100
1 668 45 _ 2001 101
2 1336 90 _ 2002 102
3 2004 135 _ 2003 103
:
99 66132 4455 _ 2099 199
Macintosh-6:interview Bill4$