Problem organizing a data set chronologically - c

I'm here asking for your help, not because I have an error, but simply because of this solution that in my head seemed quite credible despite not working.
I basically have a structure to make an appointment and I created a variable of this temporary structure to change the values ​​so that they are in ascending order, however when I show the query table in this case, but the queries appear in the order I registered them in the program.
My Struct:
typedef struct Consulta {
char nomeUtente[70];
int numSNS;
int dia;
int mes;
int ano;
int horasInicio;
int minutosInicio;
int horasFim;
int minutosFim;
} consulta;
My function that should order the values:
void organizarAgenda(int membroEscolhido, consulta agenda[][50][50], int clinicaSelecionada, int *nFuncionarios, int *nAgendas)
{
int i, j;
boolean substituir;
consulta temp;
for (i = 0; i < nAgendas[membroEscolhido]; i++)
{
for (j = 0; j < nAgendas[membroEscolhido]; j++)
if (agenda[j][membroEscolhido][clinicaSelecionada].ano > agenda[i][membroEscolhido][clinicaSelecionada].ano)
substituir = true;
if (agenda[j][membroEscolhido][clinicaSelecionada].ano == agenda[i][membroEscolhido][clinicaSelecionada].ano
&& (agenda[j][membroEscolhido][clinicaSelecionada].mes > agenda[i][membroEscolhido][clinicaSelecionada].mes))
substituir = true;
if (agenda[j][membroEscolhido][clinicaSelecionada].ano == agenda[i][membroEscolhido][clinicaSelecionada].ano
&& (agenda[j][membroEscolhido][clinicaSelecionada].mes == agenda[i][membroEscolhido][clinicaSelecionada].mes)
&& (agenda[j][membroEscolhido][clinicaSelecionada].dia > agenda[i][membroEscolhido][clinicaSelecionada].dia))
substituir = true;
if (agenda[j][membroEscolhido][clinicaSelecionada].ano == agenda[i][membroEscolhido][clinicaSelecionada].ano
&& (agenda[j][membroEscolhido][clinicaSelecionada].mes == agenda[i][membroEscolhido][clinicaSelecionada].mes)
&& (agenda[j][membroEscolhido][clinicaSelecionada].dia == agenda[i][membroEscolhido][clinicaSelecionada].dia
&& agenda[j][membroEscolhido][clinicaSelecionada].horasInicio >= agenda[i][membroEscolhido][clinicaSelecionada].horasInicio))
substituir = true;
if (substituir == true)
{
//Igualar a variavel temporario á variável agenda em i
temp.ano = agenda[i][membroEscolhido][clinicaSelecionada].ano;
temp.mes = agenda[i][membroEscolhido][clinicaSelecionada].mes;
temp.dia = agenda[i][membroEscolhido][clinicaSelecionada].dia;
temp.horasInicio = agenda[i][membroEscolhido][clinicaSelecionada].horasInicio;
temp.minutosInicio = agenda[i][membroEscolhido][clinicaSelecionada].minutosInicio;
temp.horasFim = agenda[i][membroEscolhido][clinicaSelecionada].horasFim;
temp.minutosFim = agenda[i][membroEscolhido][clinicaSelecionada].minutosFim;
//Igualar a variável agenda em i á variável agenda em j
agenda[i][membroEscolhido][clinicaSelecionada].ano = agenda[j][membroEscolhido][clinicaSelecionada].ano;
agenda[i][membroEscolhido][clinicaSelecionada].mes = agenda[j][membroEscolhido][clinicaSelecionada].mes;
agenda[i][membroEscolhido][clinicaSelecionada].dia = agenda[j][membroEscolhido][clinicaSelecionada].dia;
agenda[i][membroEscolhido][clinicaSelecionada].horasInicio = agenda[j][membroEscolhido][clinicaSelecionada].horasInicio;
agenda[i][membroEscolhido][clinicaSelecionada].minutosInicio = agenda[j][membroEscolhido][clinicaSelecionada].minutosInicio;
agenda[i][membroEscolhido][clinicaSelecionada].horasFim = agenda[j][membroEscolhido][clinicaSelecionada].horasFim;
agenda[i][membroEscolhido][clinicaSelecionada].minutosFim = agenda[j][membroEscolhido][clinicaSelecionada].minutosFim;
//Igualar a variável agenda em j á variavel temporaria
agenda[j][membroEscolhido][clinicaSelecionada].ano = temp.ano;
agenda[j][membroEscolhido][clinicaSelecionada].mes = temp.mes;
agenda[j][membroEscolhido][clinicaSelecionada].dia = temp.dia;
agenda[j][membroEscolhido][clinicaSelecionada].horasInicio = temp.horasInicio;
agenda[j][membroEscolhido][clinicaSelecionada].minutosInicio = temp.minutosInicio;
agenda[j][membroEscolhido][clinicaSelecionada].horasFim = temp.horasFim;
agenda[j][membroEscolhido][clinicaSelecionada].minutosFim = temp.minutosFim;
}
}
Thank you all in advance!

substituir is unitialized. You need to set it to false immediately after the for statement for j.
Your for loop for j is missing a trailing { so it will only iterate over the first if and not the others [as you would probably like]
As I mentioned in my comment, simplify [please ;-)]. Use pointers to simplify the code.
Your indexing is quite complex, so I can only guess at things.
I changed the comparison logic to something I understand.
Here's a simplified version. I just coded it, so it may not compile. But, it should give you some ideas how to proceed:
typedef struct Consulta {
char nomeUtente[70];
int numSNS;
int dia;
int mes;
int ano;
int horasInicio;
int minutosInicio;
int horasFim;
int minutosFim;
} consulta;
void
organizarAgenda(int membroEscolhido, consulta agenda[][50][50],
int clinicaSelecionada, int *nFuncionarios, int *nAgendas)
{
int i;
int j;
int lim = nAgendas[membroEscolhido];
int dif;
consulta temp;
for (i = 0; i < lim; i++) {
consulta *iptr = &agenda[i][membroEscolhido][clinicaSelecionada];
for (j = 0; j < lim; j++) {
consulta *jptr = &agenda[j][membroEscolhido][clinicaSelecionada];
do {
dif = iptr->ano - jptr->ano;
if (dif)
break;
dif = iptr->mes - jptr->mes;
if (dif)
break;
dif = iptr->dia - jptr->dia;
if (dif)
break;
} while (0);
if (dif <= 0)
continue;
temp = *iptr;
*iptr = *jptr;
*jptr = temp;
}
}
}
I'm [still] guessing but I think you can get a [significant] speedup by changing the for loop for j.
And, I think the for loop for i goes one too far.
So, consider:
for (i = 0; i < (lim - 1); i++) {
consulta *iptr = &agenda[i][membroEscolhido][clinicaSelecionada];
for (j = i + 1; j < lim; j++) {
consulta *jptr = &agenda[j][membroEscolhido][clinicaSelecionada];
UPDATE:
I didn't understand how a 3d array with only a 2d array assignment works int lim = nAgendas[membroEscolhido];
The value of nAgendas[membroEscolhido] is invariant across the function, so it can be "cached". I did this to simplify the code [mostly] but it also can help the compiler generate more efficient code.
I didn't notice the (-) in the middle of this line, and the -> works because it is a pointer pointing to the struct, right?
Right. The arrow operator (->) is a very powerful way to access individual struct members if you have a pointer to the given struct instance.
Note that the compiler's optimizer might be able to see that all the variables of the form: array[x][y][z].whatever could be reduced.
But, when we use intermediate pointers we're giving it a [better] clue as to what we want. And, the code is more readable by humans, so it has two good reasons to do it.
I don't understand why you put while (0)
This is a bit of a trick [of mine] to replace an if/else ladder with something that is cleaner.
It forms a "once through" loop. It would be the equivalent of:
while (1) {
if (something)
break;
if (something_else)
break;
break; // make the loop execute _only_ once
}
For a more detailed explanation, see my answer: About the exclusiveness of the cases of an if block

Related

How to find the minimum number of coins needed for a given target amount(different from existing ones)

This is a classic question, where a list of coin amounts are given in coins[], len = length of coins[] array, and we try to find minimum amount of coins needed to get the target.
The coins array is sorted in ascending order
NOTE: I am trying to optimize the efficiency. Obviously I can run a for loop through the coins array and add the target%coins[i] together, but this will be erroneous when I have for example coins[] = {1,3,4} and target = 6, the for loop method would give 3, which is 1,1,4, but the optimal solution is 2, which is 3,3.
I haven't learned matrices and multi-dimensional array yet, are there ways to do this problem without them? I wrote a function, but it seems to be running in an infinity loop.
int find_min(const int coins[], int len, int target) {
int i;
int min = target;
int curr;
for (i = 0; i < len; i++) {
if (target == 0) {
return 0;
}
if (coins[i] <= target) {
curr = 1 + find_min(coins, len, target - coins[i]);
if (curr < min) {
min = curr;
}
}
}
return min;
}
I can suggest you this reading,
https://www.geeksforgeeks.org/generate-a-combination-of-minimum-coins-that-results-to-a-given-value/
the only thing is that there is no C version of the code, but if really need it you can do the porting by yourself.
Since no one gives a good answer, and that I figured it out myself. I might as well post an answer.
I add an array called lp, which is initialized in main,
int lp[4096];
int i;
for (i = 0; i <= COINS_MAX_TARGET; i++) {
lp[i] = -1;
}
every index of lp is equal to -1.
int find_min(int tar, const int coins[], int len, int lp[])
{
// Base case
if (tar == 0) {
lp[0] = 0;
return 0;
}
if (lp[tar] != -1) {
return lp[tar];
}
// Initialize result
int result = COINS_MAX_TARGET;
// Try every coin that is smaller than tar
for (int i = 0; i < len; i++) {
if (coins[i] <= tar) {
int x = find_min(tar - coins[i], coins, len, lp);
if (x != COINS_MAX_TARGET)
result = ((result > (1 + x)) ? (1+x) : result);
}
}
lp[tar] = result;
return result;
}

Changing the contents of an array in a recursive function

I am having trouble understanding something regarding recursion and arrays.
basically, what the program does is to check what is the maximum weights of items that can be placed in two boxes. I know it's far from perfect as it is right now, but this is not the point.
Generally everything is working properly, however, now I decided that I want to see the contents of each box when the weight is maximal. For this purpose I tried using arr1 and arr2.
I don't understand why I get different results for arr1 and arr2 (the first options gives me what I want, the second does not).
This is the program:
#define N 5
int help(int items[N][2], int box1[N], int box2[N], int rules[N][N],
int optimal,int current_weight,int item,int arr1[],int arr2[])
{
if (item == N)
{
if(current_weight>optimal) //This is the first option
{
memcpy(arr1,box1,sizeof(int)*N);
memcpy(arr2,box2,sizeof(int)*N);
}
return current_weight;
}
int k = items[item][1]; int sol;
for (int i = 0; i <= k; i++)
{
for (int j = 0; i+j <= k; j++)
{
box1[item] += i; box2[item] += j;
if (islegal(items, box1, box2, rules))
{
sol = help(items, box1, box2, rules, optimal,
current_weight + (i + j)*items[item][0],item+1,arr1,arr2);
if (sol > optimal)
{
optimal = sol;
memcpy(arr1,box1,sizeof(int)*N); //This is the second option
memcpy(arr2,box2,sizeof(int)*N);
}
}
box1[item] -= i; box2[item] -= j;
}
}
return optimal;
}
int insert(int items[N][2], int rules[N][N])
{
int box1[N] = { 0 }; int arr1[N] = { 0 };
int box2[N] = { 0 }; int arr2[N] = { 0 };
int optimal = 0;
int x = help(items, box1, box2, rules,0, 0,0,arr1,arr2);
print(arr1, N);
print(arr2, N);
return x;
}
Can anyone explain what causes the difference? Why the first option is correct and the second is not? I couldn't figure it out by my own.
Thanks a lot.
This doesn't work because when you pass box1 and box2 to help, they are mutated by help. It's pretty obvious from the algorithm that you want them to not be mutated. So, we can do as follows:
int help(int items[N][2], int box1in[N], int box2in[N], int rules[N][N],
int optimal,int current_weight,int item,int arr1[],int arr2[])
{
int box1[N];
int box2[N];
memcpy(box1, box1in, sizeof(int)*N);
memcpy(box2, box2in, sizeof(int)*N);
Your algorithm may still have problems but that problem is now removed.

Segmentation Fault when returning integer

I recently joined Stackoverflow community because I had to ask this question. I've been searching for possible explanations and solutions on the website but so far nothing enlightened me as I wanted. My error is probably caused by a very specific line of code. I'm trying to create a function that reads an array of struct votes, (struct contains integer member number, char *category, char *nominee) and copies all the votes that contain the same number and category to another array of struct. Basically to show all the repeated votes.
typedef struct
{
int member;
char *categ;
char *nom;
}Vote
Vote vote(int member, char *categ, char *nom)
{
Vote result;
result.member = member;
result.categ = categ;
result.nom = nom;
return result;
}
int votes_count(Vote *v, int n, Vote *v1)
{
int result = 0;
int *index = malloc(sizeof(int) * 1000);
int a = 0;
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
if (a == 0 && v[i].member == v[j].member && strcmp(v[i].categ, v[j].categ) == 0)
{
v1[result++] = vote(v[j].member, str_dup(v[j].categ), str_dup(v[j].nom));
index[a++] = j;
}
for (int b = 0; b < a; ++b)
{
if( a > 0 && v[i].member == v[j].member && strcmp(v[i].categ, v[j].categ) == 0 && j != index[b])
{
v1[result++] = voto(v[j].member, str_dup(v[j].categ), str_dup(v[j].nom));
index[a++] = j;
}
}
}
}
return result;
}
Afterwads, it returns the number of elements of new array that contains all repetitions. I want to use an array of ints to save all line indexes so that the function doesn't read and copy the lines it already accounted.
Sorry if the code is hard to understand, if needed I can edit to be more understandable. Thanks for any answears.
P.S: I'm portuguese, sorry in advance for grammar mistakes
if your only intention is to harvest the duplicates, you only need to compare to the elements that came before an element
you don't need the index[] array
For simplicity, I used two integer arrays, you should change them to your struct arrays, also change the compare function.
unsigned fetchdups(int orig[], int dups[], unsigned count)
{
unsigned this, that, ndup=0;
for (this=1; this<count; this++){
for (that=0; that<this; that++){
/* change this to your compare() */
if(orig[that] == orig[this]) break;
}
if (this == that) continue; /* no duplicate */
dups[ndup++] = this;
}
return ndup;
}

Order array of struct by one chosen attribute in C

I'm having trouble while ordering an array of a struct that contains 3 infos types. I want to order using one of the info, then organize the other 2 infos, but I'm using heapsort and don't know how I would change the code to automatically reorganize. There is any logical hint that would help me? here's the struct
typedef struct{
int orig;
int dest;
float cost;
}infos;
thanks. i can add any info that help you people help me!
[EDIT]
void build ( Armaz x[], int n ){
int i;
float val;
int s;
int f;
for (i = 1; i<n; i++){
val = x[i].cost;
s = i;
f = (s-1)/2;
while (s>0 && x[f].cost<val){
x[s].cost = x[f].cost;
s = f;
f = (s-1) / 2;
}
x[s].cost = val;
}
}
void heapsort (infos x[], int n){
build(x,n);
int i;
int s;
int f;
float vali ;
for (i = n - 1 ; i > 0 ; i--){
vali = x[i].cost;
x[i].cost = x[0].cost;
f = 0 ;
if (i == 1){
s = -1;
}
else s = 1;
if ( i > 2 && x[2].cost > x[1].cost) s = 2 ;
while ( s >= 0 && vali < x[s].cost){
x[f].cost = x[s].cost;
f = s;
s = 2 * f + 1;
if ( s + 1 <= i - 1 && x[s].cost < x[s + 1].cost ) s++;
if (s > i-1) s = -1;
}
x[f].cost = vali;
}
}
Even if you implement your own sorting functions, I recommend you take a closer look at how the standard qsort function works.
In short: It has an argument that is a pointer to a function used for comparison. That function receives pointers to two "objects" that should be compared, and can do whatever it wants to compare the two "objects". That means one could have three different comparison functions, one for each member of your structure, and pass the appropriate one when needed.

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