increment in a loop and keeping state - c

gcc 4.4.4 c89
I have the following code and 2 structures that have to be filled.
I have 3 functions that will fill the handles for each of the devices.
However, the device_type structure will need to increment from where the last function finished.
For example:
load_resources() starts at 0 and finishes at 9
dev_types starts at 0 and finishes at 9
load_networks() starts at 0 and finishes at 9
dev_types starts at 10 and finishes at 19
load_controls() starts at 0 and finishes at 9
dev_types starts at 20 and finishes at 29
However, as I don't want to use a static or global variable is there any way I can increment a
value for this. So it will start where the last function finished.
Many thanks for any suggestions,
#define NUMBER_OF_DEVICES 10
#define NUMBER_OF_TYPES 3 /* resources
networks
controls */
int events(int evt);
int load_resources();
int load_networks();
int load_controls();
static struct device_table {
int resource_handle;
int network_handle;
int control_handle;
} dev_tbl[NUMBER_OF_DEVICES];
struct device_types {
size_t id;
int dev_handle;
int dev_type;
}dev_types[NUMBER_OF_DEVICES * NUMBER_OF_TYPES];
enum dev_name_types {RESOURCE, NETWORK, CONTROL};
/* Simulates the API calls, by returning a dummy handle */
int get_resources();
int get_networks();
int get_controls();
int main(void)
{
srand(time(NULL));
load_resources();
load_networks();
load_controls();
return 0;
}
int load_resources()
{
size_t i = 0;
for(i = 0; i < NUMBER_OF_DEVICES; i++) {
dev_tbl[i].resource_handle = get_resources();
printf("dev_tbl[i].resource_handle [ %d ]\n", dev_tbl[i].resource_handle);
dev_types[i].id = i;
dev_types[i].dev_handle = dev_tbl[i].resource_handle;
dev_types[i].dev_type = RESOURCE;
}
}
int load_networks()
{
size_t i = 0;
for(i = 0; i < NUMBER_OF_DEVICES; i++) {
dev_tbl[i].network_handle = get_networks();
printf("dev_tbl[i].network_handle [ %d ]\n", dev_tbl[i].network_handle);
dev_types[i].id = i;
dev_types[i].dev_handle = dev_tbl[i].network_handle;
dev_types[i].dev_type = NETWORK;
}
}
int load_controls()
{
size_t i = 0;
for(i = 0; i < NUMBER_OF_DEVICES; i++) {
dev_tbl[i].control_handle = get_controls();
printf("dev_tbl[i].control_handle [ %d ]\n", dev_tbl[i].control_handle);
dev_types[i].id = i;
dev_types[i].dev_handle = dev_tbl[i].control_handle;
dev_types[i].dev_type = CONTROL;
}
}

Why not change the prototypes to something like:
void load_resources(int*)
(they're not actually returning anything) then, in your main code, have:
int base = 0;
load_resources (&base);
load_networks (&base);
load_controls (&base);
Each function is then responsible for using and updating *base like this:
void load_resources (int *pBase) {
size_t i = 0;
for(i = 0; i < NUMBER_OF_DEVICES; i++, (*pBase)++) { // <-- see here!
dev_tbl[i].resource_handle = get_resources();
printf("dev_tbl[i].resource_handle [ %d ]\n", dev_tbl[i].resource_handle);
dev_types[*pBase].id = i;
dev_types[*pBase].dev_handle = dev_tbl[i].resource_handle;
dev_types[*pBase].dev_type = RESOURCE;
}
}

One option is to have each of your functions take the base index as a parameter, and returning the first available index:
int index = 0;
index = load_resources(index);
index = load_network(index);
// and so on
With this yout functions would look something like this:
int load_resources(int base_index)
{
size_t i = 0;
size_t index;
for(i = 0; i < NUMBER_OF_DEVICES; i++) {
index = base_index + i;
dev_tbl[index].resource_handle = get_resources();
//
}
return index + 1;
}
By the way, your functions do have int return types, but do not return anything.

Hold a pointer or index variable within the structure itself. It's an indicator for how far the structure has been filled up generally.

There are only two ways to persist data from one scope to the next - on the stack and on the heap. Since you have already ruled out any global variables here, that would require you to use stack variables, by passing in a parameter and returning a value, or passing in a pointer to a parameter.

Related

Adding element to array, old values turns to 0 but new shows

I have written this program where I can add pics to a staff using their names. but right now it adds the new value but the already existing values becomes 0.
this is the outcome:
type in the name you would like to add pic to
Anna
type in pic
55
1.Show existing
2.add pic to a staff
1
Adam 1,2,3,
Anna 0,0,0,55,
the rest of the code:
typedef struct Staff
{
char name[30];
int *pic;
int imagecount;
} Staff;
void printStaff(Staff *pStaff)
{
printf("%s ", pStaff->name);
if ( pStaff->pic) {
for(int i=0; i<pStaff->imagecount; i++){
printf("%d,",pStaff->pic[i]);
}
}
printf("\n");
}
void PrintList(Staff aLista[], int staffCount)
{
for (int i = 0; i < staffCount; i++) {
printStaff(&aLista[i]);
}
}
UPDATED CODE:
Staff addpic(Staff array[], int staffCount)
{
Staff newStaff = {};
printf("type in the name you would like to add pic to \n");
fgets(newStaff.name, 30, stdin);
for(int i = 0; i< staffCount; i++) {
if(strcmp(array[i].name,newStaff.name)==0) {
if(array[i].imagecount<5) {
printf("type in pic\n");
int newpic;
scanf("%d",&newpic);
array[i].imagecount++;
int *newpics = realloc(newStaff.pic, (array[i].imagecount) * sizeof(int));
newpics[array[i].imagecount-1] = newpic;
array[i].pic = newpics;
}
}
}
return newStaff;
the rest of the code:
int main(void)
{
int staffCount=0;
int input;
int test[3] = {1,2,3};
Staff myStaff[5] = { {"Adam", test, 3},{"Anna",test,3} };
staffCount=2;
do
{
printf("1.Show existing \n");
printf("2.add pic to a staff");
printf("\n");
scanf("%d", &input);
switch(input)
{
case 1:
PrintList(myStaff,staffCount);
break;
case 2:
addpic(myStaff,staffCount);
break;
default:
printf("inccorect inpput\n");
break;
}
}while (input<'1' ||input<'2');
return 0;
}
any help is appreciated, but I'm new to coding so keep that in mind.
In the addpic function you do
int *newpics = realloc(array[i].pic, ...);
One problem is that if you do it for one of the two elements you have initialized in array, then array[i].pic is pointing to the first element of an array (the array test in the main function).
Arrays can not be reallocated. If you want to reallocate the memory you need to allocate the original memory dynamically as well.
newStaff.pic is initialized to NULL and not updated then, so realloc(newStaff.pic, (array[i].imagecount) * sizeof(int)); is equivalent to malloc((array[i].imagecount) * sizeof(int));.
Elements allocated via malloc() and not initialized hae indeterminate value, and they happened to be zero in this case.
You can take over the contents by manually copying them.
int *newpics = realloc(newStaff.pic, (array[i].imagecount) * sizeof(int));
/* add this line to copy contents */
for (int j = 0; j < array[i].imagecount-1; j++) newpics[j] = array[i].img[j];
newpics[array[i].imagecount-1] = newpic;
Unfortunately, this method is not good because this may cause memory leak if addition like this to the same element of array is done multiple times.
Better way is to allocate the buffer to assign to img dynamically and pass them to realloc(). Then, realloc() will do the copying for you.
Initialization part:
int test[3] = {1,2,3};
Staff myStaff[5] = { {"Adam", test, 3},{"Anna",test,3} };
staffCount=2;
/* add this to change statically allocated arrays to dynamically allocated ones */
for (int i = 0; i < staffCOunt; i++) {
int* newpics = malloc(myStaff[i].imagecount * sizeof(int));
for (int j = 0; j < myStaff[i].imagecount; j++) newpics[j] = myStaff[i].img[j];
myStaff[i].img = newpics;
}
Updating part:
/* use array[i].pic instead of newStaff.pic */
int *newpics = realloc(array[i].pic, (array[i].imagecount) * sizeof(int));
/* then, no manual copying is required */
(error checkings are omitted)

Wrap C primitive values in CFArray of CFNumbers

What is the best way to implement a method to wrap a C array of primitive numbers into a CFArray of CFNumbers?
I want to call something like:
double values[] = {1.2345, 678.9};
CFArrayRef arr = NumberWrappedValuesArray(&values, 2, kCFNumberDoubleType);
And tried this:
CFArrayRef NumberWrappedValuesArray(void * valueArrayPtr, CFIndex count, CFNumberType numberType) {
CFMutableArrayRef array = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks);
for (int i = 0; i < count; i++) {
CFNumberRef numberWrappedValue = CFNumberCreate(NULL, numberType, &valueArrayPtr[i]);
CFArrayAppendValue(array, numberWrappedValue);
CFRelease(numberWrappedValue);
}
CFRelease(array);
return array;
}
It doesn't work (returned array has 0 elements), why and how do I fix it?
Is there a more elegant way, potentially avoiding the mutable CFArray?
Thanks!
You can use CFArrayCreate.
Example:
CFArrayRef NumberWrappedValuesArray(void *valueArrayPtr, size_t size, CFIndex count, CFNumberType numberType) {
size_t i, n;
CFArrayRef ret;
CFNumberRef *ref = malloc(sizeof(CFNumberRef) * count);
/* create array of boxed types. */
for (i = 0, n = count; i < n; ++i)
ref[i] = CFNumberCreate(NULL, numberType, ((char *)valueArrayPtr) + (size * i));
/* create CFArray. */
ret = CFArrayCreate(NULL, (const void **)ref, count, &kCFTypeArrayCallBacks);
/* release boxed types and malloc'ed array. */
for (i = 0; i < n; ++i)
CFRelease(ref[i]);
free(ref);
/* return CFArray, without releasing first! Has to be done by the caller. */
return ret;
}
Error handling omitted for clarity.

Name variables dynamically

I am creating n threads. I would like to create n variables b1,b2,b3,.,bi,..bn.
How can I do this in C? I mean to choose the name of the global variable according to the number of the thread.
thanks
Taken from NapoleonBlownapart's comment to the OP: "You can't. Variable names only exist at compile time, while threads only exist at runtime."
Use an array, with as much elements as you have threads. Then use the thread's number as index to the arrary
See some pseudo code below:
#define THREAD_MAXIMUM (42)
int b[THREAD_MAXIMUM];
thread_func(void * pv)
{
size_t i = (size_t) pv;
int bi = b[i];
...
}
int main()
{
...
for(size_t i = 0; i < THREAD_MAXIMUM; ++i)
{
b[i] = some thread specific number;
create-thread(thread_func, i) /* create thread and pass index to array element);
}
...
}
You can try with arrays or vectors(in C++). I would have preferred coding in C++ and use vector instead of C and array.
Simple implementation with array can be as follows -
#define MAX_THREAD(100)
int var[MAX_THREAD]
ThreadImpl(Params)
{
int i = (int) Params;
int vari = var[i];
}
int main()
{
for(int i = 0; i < MAX_THREAD; ++i)
{
var[i] = val; (val can be ThreadID or other value as per requirement)
pthread_create(ThreadImpl, ... other params);
}
return 0;
}

Initializing Strings in an Array of Sturts within a Struct

I have a struct gradebook with(among other things) an array of student structs that has two string fields
#define MAX_NAME_LEN 50
#define MAX_EMAIL_LEN 80
#define MAX_NUMBER_OF_STUDENTS 200
#define MAX_NUMBER_OF_ASSIGNMENTS 100
typedef struct students {
char *name;
char *email;
} Students;
typedef struct gradebook {
int number_of_students;
Students students[MAX_NUMBER_OF_STUDENTS];
int number_of_assignments;
char assignments[MAX_NUMBER_OF_ASSIGNMENTS][(MAX_NAME_LEN + 1)];
int scores[MAX_NUMBER_OF_STUDENTS][MAX_NUMBER_OF_ASSIGNMENTS];
} Gradebook;
I have an initialization function
int init_gradebook(Gradebook *book) {
int row, col, ndx, count;
book->number_of_students = 0;
count += book->number_of_students;
for(ndx = 0; ndx < MAX_NUMBER_OF_STUDENTS; ndx++) {
book->students[ndx].name = 0;
book->students[ndx].email = 0;
}
book->number_of_assignments = 0;
count += book->number_of_assignments;
for(row = 0; row < MAX_NUMBER_OF_ASSIGNMENTS; row++) {
for(col = 0; col < (MAX_NAME_LEN + 1); col++) {
book->assignments[row][col] = 0;
count += book->assignments[row][col];
}
}
for(row = 0; row < MAX_NUMBER_OF_STUDENTS; row++) {
for(col = 0; col < MAX_NUMBER_OF_ASSIGNMENTS; col++) {
book->scores[row][col] = 0;
count += book->scores[row][col];
}
}
if (count == 0) {
return 1;
} else {
return 0;
}
}
and I need to then insert, into those two string fields, the passed in strings, with my add_student function.
int add_student(Gradebook *book, char *nom, char *mail) {
int ndx, count;
if (book->number_of_students == 0) {
book->students[(book->number_of_students)].name = malloc(sizeof(51));
book->students[(book->number_of_students)].email = malloc(sizeof(81));
strcpy(book->students[(book->number_of_students)].name, nom);
strcpy(book->students[(book->number_of_students)].email, mail);
book->number_of_students++;
} else {
for (ndx = 0; ndx < book->number_of_students; ndx++) {
book->students[(book->number_of_students)].name = malloc(sizeof(51));
book->students[(book->number_of_students)].email = malloc(sizeof(81));
strcpy(book->students[(book->number_of_students)].name, nom);
strcpy(book->students[(book->number_of_students)].email, mail);
book->number_of_students++;
}
}
return 1;
}
My code compiles, but when I run it with the main function, I get a seg fault. The add_student function is what I am ultimately trying to do (copy the given string into book->student[ndx].name) If you need to see the main file or the gradebook.h file, let me know.
Edit: Thanks to all of you, this issue has been solved. The main problem, as abginfo pointed out, was my If Else + the For loop inside of it. But now I have other problems further along in my program. Haha, Thank You.
From what portion of your code I can see, I'm going to make the assumption that the init_gradebook function takes a non allocated reference to gradebook and attempts to initialize it.
In this case the gradebook reference you have has no memory allocated to it just yet. Try using the malloc() function to assign the required memory to your gradebook reference before attempting to initialize the rest of its variables.
gb = (Gradebook*)malloc(sizeof(*Gradebook));
I've changed the variable name to avoid any confusion.
To supplement varevarao's answer, you should allocate everything explicitly as a matter of habit instead of relying on segfaults to tell you something's not allocated. (Not that you necessarily do!) Messing with unallocated memory is undefined behavior, so in some cases this code does not trigger an error -
int main (void) {
Gradebook mybook;
init_gradebook(&mybook);
printf("there are %i students\n", mybook.number_of_students);
add_student(&mybook, "blerf", "blerf#gmail.com");
printf("now there are %i students\n", mybook.number_of_students);
printf("%s has an email address of %s\n", mybook.students[0].name, mybook.students[0].email);
return 0;
}
returned (on my machine)
there are 0 students
now there are 1 students
blerf has an email address of blerf#gmail.com

C Array loop through

Instead of looping through each element of an array is it possible to loop through only elements which have assignments?
In the following example I would like to loop through only three elements instead of looping through each element in the array. What are my options ? I hate to loop through thousands of elements when only handful from them are assigned based on certain logic.
main()
{
int i, intArray[10000];
intArray[334] = 30;
intArray[563] = 50;
intArray[989] = 90;
for (i = 0; i < 10000; i++)
{
printf("%d\n", intArray[i]);
}
}
Thank you for reading the post. Sorry if it a re-post. I would not find similar question in the forum.
Only indirectly:
#include <stdio.h>
int main(void)
{
int i, intArray[10000];
int active[10000];
int n_active = 0;
intArray[334] = 30;
active[n_active++] = 334;
intArray[563] = 50;
active[n_active++] = 563;
intArray[989] = 90;
active[n_active++] = 989;
for (i = 0; i < n_active; i++)
printf("%d\n", intArray[active[i]]);
return 0;
}
Or, more succinctly but not more clearly:
#include <stdio.h>
int main(void)
{
int i, intArray[10000];
int active[10000];
int n_active = 0;
intArray[active[n_active++]=334] = 30;
intArray[active[n_active++]=563] = 50;
intArray[active[n_active++]=989] = 90;
for (i = 0; i < n_active; i++)
printf("%d\n", intArray[active[i]]);
return 0;
}
Both of these programs will suffer if there's more than one assignment to the same index (that index will be stored in the active array twice). As it stands, it also doesn't check for overflow of the active array (but that shouldn't be a problem; the hypothesis is that only a few of the rows are populated), and the indexes are stored in the order that they're presented — not in key order. All these defects can be fixed, but take more code (it would probably need to be a function or two).
You can do something like this
# include <stdio.h>
int totalElements = 0;
struct
{
int index, data;
} Data[10000];
void addElement(int index, int data)
{
Data[totalElements].data = data;
Data[totalElements++].index = index;
}
main()
{
int i;
addElement(334, 30);
addElement(563, 50);
addElement(989, 90);
for (i = 0; i < totalElements; i++)
{
printf("%d %d\n", Data[i].data, Data[i].index);
}
}
Output
30 334
50 563
90 989
This also suffers the same limitations Jonathan Leffler mentioned.
EDIT
# include <stdio.h>
int totalElements = 0;
struct
{
int index, currentElement = 0, data[100];
} Data[10000];
void addElement(int index, int data)
{
int i;
for (i = 0; i < totalElements; i++)
{
if (Data[i].index == index)
{
Data[i].data[Data[i].currentElement++] = data;
return;
}
}
Data[totalElements].data[Data[totalElements].currentElement++] = data;
Data[totalElements++].index = index;
}
main()
{
int i, j;
addElement(334, 30);
addElement(334, 40);
addElement(563, 50);
addElement(563, 60);
addElement(989, 80);
addElement(989, 90);
for (i = 0; i < totalElements; i++)
{
for (j = 0; j < Data[i].currentElement; j++)
{
printf("%d %d\n", Data[i].index, Data[i].data[j]);
}
}
}
Output
334 30
334 40
563 50
563 60
989 80
989 90
Using this idea you can overcome the limitations mentioned by Jonathan Leffler.
Perhaps you could use a different data structure, like a linked list. Each node in the list could have two int values, one could be the index and the other the value. The linked list would then only contain indicies which have been assigned (and you could also have value==0, if that is somehow different to the normal, unassigned index).
The other alternative would be to use something like a Dictionary structure. There are probably Dictionary implementations for C - I would say though, if C++ is available maybe you should use it instead (unless you are specifically trying to learn or are constrained to C) - C++ has many data types available straight out of the box.

Resources