● int vectorInsert(Vector * array, int index, Data value);
I am doing
If this can be corrected according to the given statement.
I am calling it using
Vector *vect = initVector();
Data data_array[20];
for(i = 0 ; i < 20 ; i++){
data_array[i].value = (rand() % 20) + 1;
vectorInsert(vect, i, data_array[i]);
}
There are a couple of errors in your code, but the most important one is in your initVector function, you actually need to allocate memory for the vector.
You also need to do the following things:
in initVector return v instead of v->data or &v
in vectorInsert print array->data[index].value instead of array->data[index]
in vectorInsert return 1 on success, add error checking in your allocation and return 0 on memory error.
All of these except the original malloc were warnings returned by the compiler.
First, according to your specifications, max_size should be an unsigned integer, so I changed Vector to reflect this, using size_t. I also changed the related format specifiers from %d to %zu to match this new type.
Your initVector() function needed to allocate memory for a Vector, so that has been added. Furthermore, there was no need to allocate memory for the dynamic array of Data structs here, so v->data is set to NULL. This function should also return the pointer to the newly allocated memory, v, instead of a pointer to the .data field of this Vector, as you originally had.
In the vectorInsert() function, you neglected to check for memory allocation errors, so I added a check after the attempted allocation which returns 0 if there is an error. After inserting the new Data struct, your check to increment .current_size is wrong. First, you need to increment if array->current_size <= index. Next, you need to add one to the .current_size, not set .current_size to one larger than the index value. Also, when printing the inserted value here, you forgot to access the .value field. I think that this may have been due to the confusing name that you used for the Data struct that you passed into vectorInsert(). You call this struct value, so in the previous line we have array->data[index] = value, where you are assigning the struct value to array->data[index]. But in the call to printf() you want to show the value held by the struct value. Choosing better names is always a win! Finally, this function returns 1 on a successful insertion.
I added to your test code to display the contents of vect and vect->data, and also added a Data struct, test_insert, to test insertion into an arbitrary index.
Finally, you need to free memory allocations after all of this, so I added a couple of calls to free().
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
int value;
}Data;
/* Specs say that max_size should be an unsigned integer */
typedef struct{
size_t max_size; //initialize to 0
size_t current_size; //initialize to 0
Data *data; // array of integers we're storing
} Vector;
/* Modified function */
Vector * initVector(void){
Vector *v = malloc(sizeof(*v));
v->max_size=0;
v->current_size=0;
v->data = NULL;
return v;
}
int vectorInsert(Vector * array, size_t index, Data value)
{
if(index >= array->max_size)
{
array->max_size = index * 2 + 1;
printf("Inside Vect max_size is : %zu\n", array->max_size);
Data *new_array = malloc(sizeof(Data) * array->max_size);
/* Added check for allocation error */
if (new_array == NULL)
return 0;
if(array->data != NULL)
{
memcpy(new_array, array->data, sizeof(Data)*array->current_size);
free(array->data);
array->data = NULL;
}
array->data = new_array;
}
array->data[index] = value;
printf("Main : %d\n", array->data[index].value);
/* Modified current_size increment logic */
if(array->current_size <= index)
{
array->current_size += 1;
}
/* Successful insertion */
return 1;
}
int main(void)
{
size_t i;
Vector *vect = initVector();
Data data_array[20];
Data test_insert = { -5 }; // to test index insertion
for(i = 0 ; i < 20 ; i++){
data_array[i].value = (rand() % 20) + 1;
vectorInsert(vect, i, data_array[i]);
}
/* Display results */
printf("vect->max_size = %zu\n", vect->max_size);
printf("vect->current_size = %zu\n", vect->current_size);
printf("vect->data contains:\n");
for (i = 0; i < vect->current_size; i++)
printf("%d ", vect->data[i].value);
putchar('\n');
/* Insert test_insert at index 5 */
vectorInsert(vect, 5, test_insert);
/* Display results */
printf("vect->max_size = %zu\n", vect->max_size);
printf("vect->current_size = %zu\n", vect->current_size);
printf("vect->data contains:\n");
for (i = 0; i < vect->current_size; i++)
printf("%d ", vect->data[i].value);
putchar('\n');
/* Free memory allocations */
free(vect->data);
free(vect);
return 0;
}
And here is a sample of the results:
vect->max_size = 31
vect->current_size = 20
vect->data contains:
4 7 18 16 14 16 7 13 10 2 3 8 11 20 4 7 1 7 13 17
vect->max_size = 31
vect->current_size = 20
vect->data contains:
4 7 18 16 14 -5 7 13 10 2 3 8 11 20 4 7 1 7 13 17
Enable all warnings and debug info in your compiler (e.g. compile with gcc -Wall -g). Then it should warn you about
Vector * initVector(){
Vector *v; /// UNINITALIZED
v->max_size=0;
v->current_size=0;
v->data = malloc(sizeof(int)*v->max_size);
return v->data;
// return (&v);
}
So you have an undefined behavior, and that is awfully bad.
(Of course the compiler will give a lot of other warnings, and you should improve your code till you got no warnings at all. Then you should use the gdb debugger)
You might want to read about flexible array members.
Consider perhaps having at least:
Vector* createVector(int maxsize) {
if (maxsize<=0)
{ fprintf(stderr, "bad maxsize=%d\n", maxsize); exit(EXIT_FAILURE); };
Vector* v = malloc(sizeof(Vector));
if (!v) { perror("malloc Vector"); exit(EXIT_FAILURE); };
v->data = malloc(sizeof(Data)*maxsize);
if (!v->data) { perror("malloc data"); exit(EXIT_FAILURE); };
v->max_size = maxsize;
v->current_size = 0;
memset(v->data, 0, sizeof(Data)*maxsize);
return v;
}
Related
#include <stdio.h>
#define LENGTH_OF_A_MACRO 3
struct blahS
{
unsigned int groupsToTrace[LENGTH_OF_A_MACRO];
} blahS;
int main()
{
//Value hardcoded to 7 just for testing purpose. Otherwise value is assigned from another function
signed int trace = 7; //trace reads value of range [0-7] from a function
unsigned int ToTrace[LENGTH_OF_A_MACRO];
unsigned int number = 0;
unsigned int noOfGroups = 100;
if (trace != 0)
{
if ((trace == 1)) //b'001
{
ToTrace[number] = noOfGroups / 8;
number++;
}
if ((trace == 4)) //b'100
{
ToTrace[number] = noOfGroups / 2;
number++;
}
if ((trace == 7)) //b'111
{
ToTrace[number] = noOfGroups * 7 / 8;
number++;
}
}
struct blahS blah;
blah.groupsToTrace[LENGTH_OF_A_MACRO] = ToTrace[number]; //Compilation-error
return 0;
}
Basically this is an if-loop which checks and decides groupToTrace based on bit-mapping for a trace value allocated. At the last line i got a compilation error saying - Array index 3 is past the end of the array. I am assigning the calculated groupToTrace values to newPointer_p->groupsToTrace[3] where groupsToTrace[3] is stored in a struct
Question is I got a compilation error as mentioned above with out of bounds access to the array as i understand. But i don't understand where is the mistake.
Compiler version gcc.x86_64 4.8.5-39.el7 #GSS-RHEL7
Any clues or hints highly appreciated. Thanks in Advance!
You seem to misunderstand what this line is doing:
blah.groupsToTrace[LENGTH_OF_A_MACRO] = ToTrace[number];
This is not copying the entire contents of one array to another. It is copying index number of ToTrace to index LENGTH_OF_A_MACRO of blah.groupsToTrace. Both of these indices have the value 3 which is out of bounds for both arrays, as an array of size 3 has indices 0, 1, and 2.
You either need a loop to copy the elements:
int i;
for (i=0; i<number; i++) {
blah.groupsToTrace[i] = ToTrace[i];
}
Or you could use memcpy:
memcpy(blah.groupsToTrace, ToTrace, sizeof(blah.groupsToTrace));
This is a tricky problem that I have been thinking about for a long time and have yet to see a satisfactory answer anywhere. Lets say I have a large int array of size 10000. I can simply declare it in the following manner:
int main()
{
int foo[10000];
int i;
int n;
n = sizeof(foo) / sizeof(int);
for (i = 0; i < n; i++)
{
printf("Index %d is %d\n",i,foo[i] );
}
return 0;
}
It is pretty clear that each index in the array will hold a random assortment of numbers before I formally initialize them:
Index 0 is 0
Index 1 is 0
Index 2 is 0
Index 3 is 0
.
.
.
Index 6087 is 0
Index 6088 is 1377050464
Index 6089 is 32767
Index 6090 is 1680893034
.
.
.
Index 9996 is 0
Index 9997 is 0
Index 9998 is 0
Index 9999 is 0
Then lets say that I initialize select index ranges of my array with values that hold a specific value for the program as a whole and must be preserved, with the goal of passing in those values for subsequent operation to some function:
//Call this block 1
foo[0] = 0;
foo[1] = 7;
foo[2] = 99;
foo[3] = 0;
//Call this block 2
foo[9996] = 0;
foo[9997] = 444;
foo[9998] = 2;
foo[9999] = 0;
for (i = 0; i < (What goes here?); i++)
{
//I must pass in only those values initialized to select indices of foo[] (Blocks 1 and 2 uncorrupted)
//How to recover those values to pass into foo_func()?
foo_func(foo[]);
}
Some of those values that I initialized foo[] with overlap with pre-existing values in the array before formally initializing the array myself. How can I pass in just the indices of the array elements that I initialized, given that there are multiple index ranges? I just can't figure this out. Thanks for any and all help!
EDIT:
I should also mention that the array itself will be read from a .txt file. I just showed the initialization in the code for illustrative purposes.
There's a number of ways you can quickly zero out the memory in the array, either while initializing or after.
For an array on the stack, initialize it with zeros. {0} is shorthand for that.
int foo[10000] = {0};
For an array on the heap, use calloc to allocate memory and initialize it with 0's.
int *foo = calloc(10000, sizeof(int));
If the array already exists, use memset to quickly overwrite all the array's memory with zeros.
memset(foo, 0, sizeof(int) * 10000);
Now all elements are zero. You can set individual elements to whatever you like one by one. For example...
int main() {
int foo[10] = {0};
foo[1] = 7;
foo[2] = 99;
foo[7] = 444;
foo[8] = 2;
for( int i = 0; i < 10; i++ ) {
printf("%d - %d\n", i, foo[i]);
}
}
That will print...
0 - 0
1 - 7
2 - 99
3 - 0
4 - 0
5 - 0
6 - 0
7 - 444
8 - 2
9 - 0
As a side note, using only a few elements of a large array is a waste of memory. Instead, use a hash table, or if you need ordering, some type of tree. These can be difficult to implement correctly, but a library such as GLib can provide you with good implementations.
Introduction
I'm making a strong assumption on your problem, and it is sparsness (a majority of the elements in your array will remain zero).
Under this assumption I would build the array as a list. I'm including a sample code, that it is not complete and it is not intended to
be---you should do your own homework :)
The core object is a struct with a pointer to a begin element and the size:
typedef struct vector {
size_t size;
vector_element_t * begin;
} vector_t;
each element of the vector has its own index and value and a pointer to the next element in a list:
typedef struct vector_element vector_element_t;
struct vector_element {
int value;
size_t index;
vector_element_t *next;
};
on this basis we can build a dynamical vector as a list, by dropping a constraint on the ordering (it is not needed, you can modify this code
to maintain the ordering), using some simple custom methods:
vector_t * vector_init(); // Initialize an empty array
void vector_destroy(vector_t* v); // Destroy the content and the array itself
int vector_get(vector_t *v, size_t index); // Get an element from the array, by searching the index
size_t vector_set(vector_t *v, size_t index, int value); // Set an element at the index
void vector_delete(vector_t *v, size_t index); // Delete an element from the vector
void vector_each(vector_t *v, int(*f)(size_t index, int value)); // Executes a callback for each element of the list
// This last function may be the response to your question
Test it online
The main example
This is a main that uses all this methods and prints in console:
int callback(size_t index, int value) {
printf("Vector[%lu] = %d\n", index, value);
return value;
}
int main() {
vector_t * vec = vector_init();
vector_set(vec, 10, 5);
vector_set(vec, 23, 9);
vector_set(vec, 1000, 3);
printf("vector_get(vec, %d) = %d\n", 1000, vector_get(vec, 1000)); // This should print 3
printf("vector_get(vec, %d) = %d\n", 1, vector_get(vec, 1)); // this should print 0
printf("size(vec) = %lu\n", vec->size); // this should print 3 (the size of initialized elements)
vector_each(vec, callback); // Calling the callback on each element of the
// array that is initialized, as you asked.
vector_delete(vec, 23);
printf("size(vec) = %lu\n", vec->size);
vector_each(vec, callback); // Calling the callback on each element of the array
vector_destroy(vec);
return 0;
}
And the output:
vector_get(vec, 1000) = 3
vector_get(vec, 1) = 0
size(vec) = 3
Vector[10] = 5
Vector[23] = 9
Vector[1000] = 3
size(vec) = 3
Vector[10] = 5
Vector[1000] = 3
The callback with the function vector_each is something you really should look at.
Implementations
I'm giving you some trivial implementations for the functions in the introdution. They are not complete,
and some checks on pointers should be introduced. I'm leaving that to you. As it is, this code is not for production and under some circumstances can also overflow.
The particular part is the search of a specific element in the vector. Every time you tranverse the list,
and this is convenient only and only if you have sparsity (the majority of your index will always return zero).
In this implementation, if you access an index that is not enlisted, you get as a result 0. If you don't want this
you should define an error callback.
Initialization and destruction
When we initialize, we allocate the memory for our vector, but with no elements inside, thus begin points to NULL. When we destroy the vector we have not only to free the vector, but also each element contained.
vector_t * vector_init() {
vector_t * v = (vector_t*)malloc(sizeof(vector_t));
if (v) {
v->begin = NULL;
v->size = 0;
return v;
}
return NULL;
}
void vector_destroy(vector_t *v) {
if (v) {
vector_element_t * curr = v->begin;
if (curr) {
vector_element_t * next = curr->next;
while (next) {
curr = curr->next;
next = next->next;
if (curr)
free(curr);
}
if (next)
free(next);
}
free(v);
}
}
The get and set methods
In get you can see how the list works (and the same concept
is used also in set and delete): we start from the begin, and
we cross the list until we reach an element with an index equal
to the one requested. If we cannot find it we simply return 0.
If we need to "raise some sort of signal" when the value is
not found, it is easy to implement an "error callback".
As long as sparsness holds, searching in the whole array for an index is a good compromise in terms of memory requirements, and efficiency may be not an issue.
int vector_get(vector_t *v, size_t index) {
vector_element_t * el = v->begin;
while (el != NULL) {
if (el->index == index)
return el->value;
el = el->next;
}
return 0;
}
// Gosh, this set function is really a mess... I hope you can understand it...
// -.-'
size_t vector_set(vector_t *v, size_t index, int value) {
vector_element_t * el = v->begin;
// Case 1: Initialize the first element of the array
if (el == NULL) {
el = (vector_element_t *)malloc(sizeof(vector_element_t));
if (el != NULL) {
v->begin = el;
v->size += 1;
el->index = index;
el->value = value;
el->next = NULL;
return v->size;
} else {
return 0;
}
}
// Case 2: Search for the element in the array
while (el != NULL) {
if (el->index == index) {
el->value = value;
return v->size;
}
// Case 3: if there is no element with that index creates a new element
if (el->next == NULL) {
el->next = (vector_element_t *)malloc(sizeof(vector_element_t));
if (el->next != NULL) {
v->size += 1;
el->next->index = index;
el->next->value = value;
el->next->next = NULL;
return v->size;
}
return 0;
}
el = el->next;
}
}
Deleting an element
With this approach it is possible to delete an element quite easily, connecting
curr->next to curr->next->next. We must though free the previous curr->next...
void vector_delete(vector_t * v, size_t index) {
vector_element_t *curr = v->begin;
vector_element_t *next = curr->next;
while (next != NULL) {
if (next->index == index) {
curr->next = next->next;
free(next);
return;
} else {
curr = next;
next = next->next;
}
}
}
An iteration function
I think this is the answer to the last part of your question,
instead passing a sequence of indexes, you pass a callback to the vector.
The callback gets and sets value in a specific index. If you want to
operate only on some specific indexes, you may include a check in the
callback itself. If you need to pass more data to the callback, check
the very last section.
void vector_each(vector_t * v, int (*f)(size_t index, int value)) {
vector_element_t *el = v->begin;
while (el) {
el->value = f(el->index, el->value);
el = el->next;
}
}
Error callback
You may want to raise some out of bounds error or something else. One solution is to enrich your list with function pointer that represent a callback that should be called when your user sk for an undefined element:
typedef struct vector {
size_t size;
vector_element_t *begin;
void (*error_undefined)(vector *v, size_t index);
} vector_t
and maybe at the end of your vector_get function you may want to do something like:
int vector_get(vector_t *v, size_t index) {
// [ . . .]
// you know at index the element is undefined:
if (v->error_undefined)
v->error_undefined(v, index);
else {
// Do something to clean up the user mess... or simply
return 0;
}
}
usually it is nice to add also an helper function to set the callback...
Passing user data to "each" callback
If you want to pass more data to the user callback, you may add a void* as last argument:
void vector_each(vector_t * v, void * user_data, int (*f)(size_t index, int value, void * user_data));
void vector_each(vector_t * v, void * user_data, int (*f)(size_t index, int value, void * user_data)) {
[...]
el->value = f(el->index, el->value, user_data);
[...]
}
if the user do not need it, he can pass a wonderful NULL.
My program parses code, and as it parses code I need to keep track of how many instances of each keywords it goes through every x number of lines (probably every 10 lines or so), from this information I plan on later creating a histogram with gnuplot but that's not important.
So there's 13 keywords, I can easily keep count of them with an array of 0s where each index represents a keyword and whenever I find a keyword I increase it's index by 1. Ok simple
int keywordcount[13]={0};
The thing is that I need to create a new keywordcount every 10 lines, and I don't know how many code lines the file has. So this tells me thatI should have a dynamic array of keywordcount arrays.
How do I declare this dynamic array of arrays in C and how do I add to it keywordcount arrays? I'm still confused by multidimensional arrays in C. I don't know if I should declare it as an array of pointers or what, and I don't know how I would go about assigning it a new keywordcount array which would not disappear when the function that creates keywordcount returns. Let me know if something isn't clear.
You can use malloc() or calloc() to create a dynamic array of static arrays. For example, this defines keywordcount_arr as a pointer to an array of 13 ints (here enough memory is allocated for max_lines such arrays):
size_t max_lines = 10;
int (*keywordcount_arr)[13] = calloc(max_lines, sizeof *keywordcount_arr);
It may make the code a little easier to read and write if a typedef is used here:
typedef int KW_Count[13];
/* ... */
KW_Count *keywordcount_arr = calloc(max_lines, sizeof *keywordcount_arr);
You can index into the allocated memory using 2d array indexing:
for (size_t i = 0; i < 13; i++) {
keywordcount_arr[0][i] = i;
}
Or, if an existing array must be stored in the dynamic array, memcpy() can be used. If the dynamic array needs to grow, realloc() can be used. And realloc() can be used again to trim the dynamic allocation to final size:
max_lines *= 2;
KW_Count *temp = realloc(keywordcount_arr,
sizeof *keywordcount_arr * max_lines);
Here is an example program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUM_KEYWORDS 13
typedef int KW_Count[NUM_KEYWORDS];
int main(void)
{
size_t max_lines = 10;
size_t num_lines = 0;
KW_Count *keywordcount_arr = calloc(max_lines, sizeof *keywordcount_arr);
if (keywordcount_arr == NULL) {
perror("Allocation failure");
/* Handle error... perhaps: */
exit(EXIT_FAILURE);
}
/* Store keyword counts directly in keywordcount_arr[] */
++num_lines;
for (size_t i = 0; i < NUM_KEYWORDS; i++) {
keywordcount_arr[0][i] = i;
}
/* Or use memcpy() if an existing array must be stored */
++num_lines;
KW_Count keywordcount = { 0, 2, 0, 0, 3, 1, 0, 0, 0, 1, 2, 0, 1 };
memcpy(keywordcount_arr[1],
keywordcount,
sizeof *keywordcount * NUM_KEYWORDS);
/* Use realloc() to grow the dynamic array as needed */
max_lines *= 2;
KW_Count *temp = realloc(keywordcount_arr,
sizeof *keywordcount_arr * max_lines);
if (temp == NULL) {
perror("Unable to reallocate");
/* Handle error */
} else {
keywordcount_arr = temp;
}
/* Use realloc() to trim the dynamic array to final size */
temp = realloc(keywordcount_arr, sizeof *keywordcount_arr * num_lines);
if (temp == NULL) {
perror("Unable to reallocate");
/* Handle error */
} else {
keywordcount_arr = temp;
}
/* Display array contents */
for (size_t i = 0; i < num_lines; i++) {
for (size_t j = 0; j < NUM_KEYWORDS; j++) {
printf("%5d", keywordcount_arr[i][j]);
}
putchar('\n');
}
/* Cleanup */
free(keywordcount_arr);
return 0;
}
Program output:
0 1 2 3 4 5 6 7 8 9 10 11 12
0 2 0 0 3 1 0 0 0 1 2 0 1
Make an assumption of how many keywordcounts will be created. Let's say that you are almost sure that 10 of them will be created.
You can dynamically declare a 2D array, of 10 rows and 13 columns.
Now keywordcount[0] will be the index of the first keywordcount array (which has size 13), and so on.
Now, if in action you see that you need more than 10 keywordcount arrays, you could use realloc() to dynamically increase the size of your 2D array.
PS: A good tip would be to double the size of your 2D array in rows every time you need to increase its size (instead of increasing by one row every time, so that you can avoid rellocations, which can be harm performance in some cases).
Don't touch 2D arrays, arrays of arrays, arrays of pointers, pointers to arrays or any such nonsense.
Wrap your statically-sized array in a struct.
typedef struct
{
int keyword_count[13];
} fragment_info;
Have a dynamic array of fragment_info like you would create any other dynamic array:
fragment_info* infos = malloc(initial_capacity * sizeof(*infos));
....
fragment_info* new_infos = realloc(infos, new_capacity * sizeof(*new_infos));
Now if you want to store additional information about your 10-line fragments, you have a natural place to keep it. Just add more fields to the struct.
First of, I'll admit I don't know much about C and pointers, but I've been reading up and have yet to find a solution. I have also tried some solutions found here on SO but none have worked.
The info to fill the structs, as well as the size of the array, is read from a file. So, I want to declare the array in main(), to use in further processing and pass it by reference to read_p5_info() where it is initialized and filled. 'configs' is to be filled by the configurations() function.
typedef struct pentomino_info pentomino_info;
struct pentomino_info {
char name;
int orientations;
int blocks[5][2];
int configs[8];
};
int read_p5_info(int *npieces, int *matrix_size, pentomino_info **pieces) {
// piece info is read from file
// npiece and matrix_size are also read from the file
// With file I'm testing with, npieces = 12 and matrix_size = 5
*pieces = malloc(*npieces * sizeof *pieces);
for (p = 0 ; p < *npieces ; p++) {
pieces[p] = malloc(sizeof *pieces[p]);
ret = fscanf(fp, "%c %*d %d %d %*d %*d %*f", &pieces[p]->name, &p5_rotations, &p5_flips);
pieces[p]->orientations = p5_rotations * p5_flips;
// read p5 blocks
int b = 0;
for (l = *matrix_size - 1 ; l >= 0 ; l--) {
for (c = 0 ; c < *matrix_size ; c++) {
// p5_char is a char read from the file
if(p5_char == '#' || p5_char == 'X') {
pieces[p]->blocks[b][0]=c;
pieces[p]->blocks[b][1]=l;
b++;
}
}
}
}
return 0;
}
int main() {
int npieces, matrix_size;
pentomino_info *pieces; // array of p5 pieces
int ret;
ret = read_p5_info(&npieces, &matrix_size, &pieces);
// configurations() operates on each piece individually
configurations(matrix_size, &pieces[k]);
}
The pieces I'm talking about are Pentominos. npieces is the number of pentaminos the file has information for, matrix_size is because pentamino_info.blocks has coordinates X,Y of the placement of each block in a matrix_size x matrix_size matrix.
I get segfault at the end of main(). pieces[0] seems fine but still gives me segfault, and the others are just malformed.
I tried to make the code a bit more compact by removing some parts that didn't seemed relevant, if I overdid it let me know. Thanks in advance for any help.
*pieces = malloc(*npieces * sizeof *pieces); allocates the wrong amount of memory. Should be sizeof **pieces. The pattern is P = malloc(N * sizeof *P); as a cognitive cross-check, check that there is one more star on the front of the argument to sizeof.
pieces[p]->x should be (*pieces)[p].x, you make this error in multiple places. In array notation, you wrote pieces[p][0].x but the correct indexing is pieces[0][p].x. The pointer pieces only points to one pointer, which then points to the first element of an array of infos.
If this is confusing I would recommend using "normal" pointers in your function, and then implementing the return-by-reference at the end, e.g.:
int n_pie = 12; // or whatever you read
pentomino_info *pie = malloc(n_pie * sizeof *pie);
// ...
pie[p].orientations = bla;
// ...
*npieces = n_pie;
*pieces = pie;
return 0;
I have some very very basic idea what a struct is and how it works.
My goal is to create an attendance-program using structure:
input: worker, time he came to work, time he left - he can leave and come multiple times (lunch break for example)
output: how many hours did each the longest worker work and who was he.
For example:
+ 8:00:00 100
+ 8:50:00 105
- 9:30:00 100
- 18:20:00 105
- 19:00:00 100
- 17:00:00 100
+ 18:00:00 100
+ 9:00:00 200
+ 10:00:00 100
- 15:00:00 200
Output:
Longest work time: 9:30:00
Longest workers: 100, 105
My original idea was to use struct this way:
typedef struct work {
int *arrivals;
int *departures;
int *result;
} WORK;
WORK 66, 100, 105, 200;
Then I would dynamically allocate memories for arrivals and departures, sort them and compare elements of arrival[i] and departure[i].
The problem with this is that the number of elements (workers) may be varying and you cannot dynamically add new elements into structures.
So how can I change the structure to suit my needs?
If the number of workers is not known ahead of time, but once known will be fixed, dynamically allocate an array of WORKs. This would be done in exactly the same way you are doing arrivals, except you'd use you work struct instead of the timestruct.
If the number will change over time, you can either use realloc to do the above but change its size when needed, or use a more dynamic structure (like a linked list). realloc is similar to malloc, except that it takes a pointer & a new size, and modifies the thing it points to (possibly moving it) to make it the new size. For a linked list, you need to (at least) add a field to your struct which is a pointer to that same kind of struct, which is used to tell you where the next item in the list is.
As you can see, there are a number of ways to approach this problem. The primary consideration boils down to How do I want to handle my struct?, an array of structs? or an array of pointers to struct?. Both have advantages and disadvantages.
The biggest disadvantage of choosing an array of structs is you will bear the burden of keeping track of all of the indexes associated with the array, as well as the time array within each struct. Choosing an array of pointers to struct helps a bit by allowing you to initialize a block of pointers to NULL. As you add a worker, instead of NULL, you have an address in the pointer. This allows you to iterate through your array of pointers with a simple while (!NULL) {do stuff...}
The second little twist comes in using calloc instead of malloc. By using calloc, you initialize the memory allocated to zero/NULL. This can apply equally to an array of structs or an array of pointers to struct. This provides the ability to use the while (!NULL) {do stuff...} iteration. (the indexing is a bit more involved with an array of structs)
The remainder of the code should be fairly readable and straight forward. Here, we define an INITWKR value of 25 to allocate in initial block of pointers to struct. The struct is defined with several additional members useful in your worker with the most time calculations. In fact, aside from keeping track of the time in/time out, there is no reason to store an array of values within each worker's struct. In the code, while the (minutes worked for each shift) is stored in the time array in each struct, the actual date/time code is omitted. That would just clutter the logic for purposes of the example.
As each new worker is entered, a new struct is allocated for him and the pointer value is stored in the array of pointers to struct. The input loop checks whether that name already exists (has a struct), if so, then additional time is added and no new struct allocation is needed. During each input iteration, you will need to check whether you have exhausted your allocated pointers or allocated time array and realloc as needed. I have placed comments in the code and included the necessary test variables, but omitted the reallocation code to prevent cluttering the worker/time logic.
When the input loop is completed (just hit [enter] instead of providing input), all worker times worked are printed and the worker with the most time is shown. The program then takes care to free all dynamically allocated memory and then exits.
Take a look, the code is commented fairly well. If you get stuck, just drop a comment.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define INITWKR 25
typedef struct {
char *name; /* worker name */
int *time; /* time array (min) */ /* optional */
unsigned entries; /* entries in time */
unsigned size; /* allocated size */ /* realloc test */
unsigned total; /* total time (min) */
} worker;
int main () {
char *name = NULL; /* name input */
int tio = 0; /* time input */
int idx = 0; /* workers index */
int idxmax = 0; /* index max time */
int tdx = 0; /* time index */
int tmax = 0; /* max worker time */
char exist = 0; /* wkr exists flag */
int wkrsz = INITWKR;/* num of wkr ptrs */
/* create INITWKR pointers to struct (initialize NULL) */
worker **wkrs = calloc (INITWKR, sizeof (*wkrs));
printf ("\nPunch the clock, enter name & minutes worked ([enter] alone to end)\n");
/* input loop, read name and minutes worked for each shift */
while (printf ("\n name: ") && scanf ("%m[^\n]%*c", &name) >= 1 &&
printf (" time: ") && scanf ("%d%*c", &tio) >= 1 )
{
idx = 0; /* reset loop vars */
exist = 0;
while (wkrs[idx]) /* check each filled worker */
{
/* check if already has struct */
if (strcmp (wkrs[idx]->name, name) == 0) {
exist = 1;
break;
}
idx++; /* idx points to first avail pointer at end */
}
/* if (idx >= INITWKR - 1) reallocate poiner array */
if (!exist) {
/* add new worker */
wkrs[idx] = malloc (sizeof (**wkrs));
wkrs[idx]-> name = strdup (name);
wkrs[idx]-> time = calloc (INITWKR, sizeof (int));
wkrs[idx]-> entries = 0;
wkrs[idx]-> size = INITWKR;
wkrs[idx]-> total = 0;
}
/* add time to worker */
tdx = 0;
while ((wkrs[idx]-> time)[tdx])
tdx++;
/* if (tdx >= wkrs[idx]-> size - 1) reallocate wkrs[idx]-> time, increment size */
(wkrs[idx]-> time)[tdx] = tio;
wkrs[idx]-> entries++;
wkrs[idx]-> total += tio;
if (wkrs[idx]-> total > tmax) {
tmax = wkrs[idx]-> total;
idxmax = idx;
}
}
if (name) free (name); /* free memory allocated by scanf */
printf ("\nWorker Time Summary:\n\n");
idx = 0;
while (wkrs[idx]) { /* output worker name/time & max */
if (idx == idxmax)
printf (" Worker[%2d] : %-24s time: %d (max time)\n", idx, wkrs[idx]->name, wkrs[idx]->total);
else
printf (" Worker[%2d] : %-24s time: %d\n", idx, wkrs[idx]->name, wkrs[idx]->total);
idx++;
}
printf ("\n");
idx = 0;
while (wkrs[idx]) { /* free dynamically allocated mem */
if (wkrs[idx]->name) free (wkrs[idx]->name);
if (wkrs[idx]->time) free (wkrs[idx]->time);
if (wkrs[idx]) free (wkrs[idx++]);
}
return 0;
}
example:
$ ./bin/workers
Punch the clock, enter name & minutes worked ([enter] alone to end)
name: JD Clark
time: 38
name: Mike Wu
time: 34
name: JD Clark
time: 39
name: Mike Wu
time: 53
name: JD Clark
time: 64
name: Tim Taylor
time: 55
name:
Worker Time Summary:
Worker[ 0] : JD Clark time: 141 (max time)
Worker[ 1] : Mike Wu time: 87
Worker[ 2] : Tim Taylor time: 55
I wrote you a little code to show you how would this work. Idea is to have dynamic arrays for both workers and arrivals/departures.
If you know how to dynamically allocate a memory for some array a for example:
int *a;
a = (int*) malloc(100*sizeof(int));
Then you know how to do it with structs:
struct s_name *my_s; // s_name is some random name of structure
my_s = (s_name*) malloc(100*sizeof(s_name));
And therefore you know how to allocate memory for some array inside a structure.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int h, m, s; // hour, minutes, seconds
} time;
typedef struct {
time *arrival;
time *departure;
time result;
int n_of_arrivals; // to keep track how many we have
int n_of_departures;
} work;
work *workers;
int main(void) {
int N;
printf("How many entries do you have?\n> ");
scanf("%d", &N);
// initially create space for 100 workers
workers = (work*) malloc(100*sizeof(work));
int number_of_workers = 100;
for (int n = 0; n < N; n++) {
char event; // this is '+' or '-'
int h, m, s, id;
scanf(" %c %d:%d:%d%d", &event, &h, &m, &s, &id);
// last position where we can put our worker is number_of_workers - 1
if (id > number_of_workers - 1) {
number_of_workers = id + 1;
// realloc memory for storing workers
workers = (work*) realloc(workers, number_of_workers*sizeof(work));
}
if (event == '+') {
// add 1 to amount of arrivals
workers[id].n_of_arrivals += 1;
int len = workers[id].n_of_arrivals;
// realloc memory for keeping arrivals of worker
workers[id].arrival = (time*) realloc(workers[id].arrival, len*sizeof(time));
// finally store new time
time *arrival = workers[id].arrival;
arrival[len - 1].h = h;
arrival[len - 1].m = m;
arrival[len - 1].s = s;
} else {
// this is the same as for adding arrivals
workers[id].n_of_departures += 1;
int len = workers[id].n_of_departures;
workers[id].departure = (time*) realloc(workers[id].departure, len*sizeof(time));
time *departure = workers[id].departure;
departure[len - 1].h = h;
departure[len - 1].m = m;
departure[len - 1].s = s;
}
}
for (int i = 0; i < number_of_workers; i++) {
// skip worker who doesn't have track of any arrivalls or depratures
if (!workers[i].n_of_arrivals && !workers[i].n_of_departures)
continue;
printf("Worker %d:\n", i);
// print nicely arrivals
if (workers[i].n_of_arrivals) {
int len = workers[i].n_of_arrivals;
printf("Arrivals:\n");
for (int k = 0; k < len; k++)
printf("%d:%d:%d\n", workers[i].arrival[k].h, workers[i].arrival[k].m, workers[i].arrival[k].s);
}
// // print nicely depratures
if(workers[i].n_of_departures) {
int len = workers[i].n_of_departures;
printf("Departures:\n");
for (int k = 0; k < len; k++)
printf("%d:%d:%d\n", workers[i].departure[k].h, workers[i].departure[k].m, workers[i].departure[k].s);
}
printf("\n");
}
return 0;
}
I didn't wrote an algorithm for calculating the result. I will leave that to you. :)