Array of pointers to the struct - c

I am coding in C a Zoo for a school project. Where there are Areas and Animals within it. We must use dynamic structures. I am trying to do the Areas and I am stuck. I am using a linked list.
Structure
typedef struct area Area, *pArea;
struct area{
char id[10];
int size, nadj;
pArea prox; //for linked list
pArea adj[3]; ///array of pointers to the struct area
};
Filling the list
void fill(pArea p){
printf("ID: ");
scanf(" %10[^\n]", p->id);
printf("Size: ");
scanf(" %d", &p->size);
printf("Nadj: ");
scanf(" %d", &p->nadj);
if(p->nadj == 0)
for(int i = 0; i < p->nadj; i++)
p->adj[i] = NULL;
else
//stuck here. HELP
}
p->prox = NULL;
}
AreaA 500 2 AreaB AreaC
Where AreaA is the id, 500 is the size variable, 2 is the number of Areas (nadj) that will be near the AreaA, following with the areas. Now, my teacher said that the areas near the id Area must be stored in a array of pointers to the struct Area (pArea adj[3], it must be in max 3 Areas) but I don't know how to fill that array while only using the name of the areas as they are on the above example when they are of type struct Area and not an array.

You need to maintain some kind of map from area names to areas. Then
for (int i = 0; i < p->nadj; i++) {
name = read_name();
p->adj[i] = find_area_by_name(name);
}
where find_area_by_name, well, should do what its name suggests. Depending on the amount of areas you need to handle (and level of the class) you may implement it as simple as linear lookup, or as fancy as AVL tree.
BTW,
if(p->nadj == 0)
for(int i = 0; i < p->nadj; i++)
p->adj[i] = NULL;
is effectively a no-op. Since the loop is entered only when p-nadj == 0, it is equivalent to
for(int i = 0; i < 0; i++)

Related

How do i keep the rest of an array of strings in C from filling with junk?

I'm working on a practice program where the user inputs a list of names. I've got the array of strings set to 50 long to give the user plenty of space, but if they are done, they can type 'quit' to stop typing. how can i keep the rest of the array from filling with junk or possibly shrink it to fit only the entered list.
#include <stdio.h>
#include <string.h>
int main()
{
char list[50][11];
char temp[11];
int index;
printf("Input a list of names type 'quit' to stop\n")
for(index = 0; index < 50; index++)
{
scanf(" %10s", temp);
if(strcmp(temp, "quit") != 0)
{
strcpy(list[index], temp);
}
else
{
index = 50;
}
}
for(int index = 0; index < 50; index++)
{
puts(list[index]);
}
return 0;
}
IMO this is a Zen of Programming question, and UnholySheep is prodding you to think in the right direction.
What is Junk? You have told the computer you need a list of 50 things, but you didn't tell it what to put in all of those list entries. So the computer just uses whatever memory it has lying around, and the odds of a particular byte being whatever value you decide is Not Junk is something like 1:256.
Of course, the Zen here is not the answer to the question "What is Junk", but rather understanding that there is Junk and Not Junk, and the only Not Junk is that which you have arranged for to exist.
So, if you don't know that a memory address does not contain Junk, then it does.
The solution to your programming question then, is to keep track of how many list entries are Not Junk. There are two common approaches used in C for this:
keep track of the length of your list, or
put a special value at the end of your list
how can i keep the rest of the array from filling with junk (?)
1) Use index. Simply keep track of how much was used. Do not access the unused portion of the array
for(int i = 0; i < index; i++) {
puts(list[i]);
}
2) Mark the next unused with a leading null character.
if (index < 50) list[index][0] = '\0';
for(int i = 0; i < 50 && list[i][0]; i++) {
puts(list[i]);
}
3) Re-architect: use a right-sized allocation array (below), a link-list, etc.
or possibly shrink it to fit only the entered list (?)
Once an array is defined, its size cannot change.
Yet a pointer to an allocated memory can be re-allocated.
Here list is a pointer to array 11 of char
char (*list)[11] = malloc(sizeof *list * 50); // error checking omitted for brevity
....
// fill up to 50
....
list = realloc(sizeof *list * index); // error checking omitted for brevity
just keep a count of entered values
int count = 0;
printf("Input a list of names type 'quit' to stop\n")
for(index = 0; index < 50; index++)
{
scanf(" %10s", temp);
if(strcmp(temp, "quit") != 0)
{
strcpy(list[index], temp);
count++;
}
else
{
index = 50;
}
}
for(int index = 0; index < count; index++)
{
puts(list[index]);
}

Merge sort in array of structs

I have an array of structs, where each object is a student with a name and a grade, and I'm trying to merge sort this array (I want to sort them by grade in ascending order).
Here is the Student Struct:
struct Student
{
char grade[42];
char city[42];
};
grade is a char because I assign the grade value by getting an input from the user with fgets and sscanf.
I don't think it's necessary to put my whole code of the merge-sort algorithm but I want to share this part which I think might be problematic ?
int firstHalfSize = midElement - firstElement + 1;
int secondHalfSize = lastElement - midElement;
struct Student firstHalfArray[firstHalfSize];
struct Student secondHalfArray[secondHalfSize];
char *p;
char *s;
int index1 = 0;
int index2 = 0;
int mergedArrIndex = firstElement;
while (index1 < firstHalfSize && index2 < secondHalfSize)
{
if (strtol(firstHalfArray[index1].grade, &p, 10) <= strtol(secondHalfArray[index2].grade, &s, 10))
{
arr[mergedArrIndex] = firstHalfArray[index1];
index1++;
}
else
{
arr[mergedArrIndex] = secondHalfArray[index2];
index2++;
}
mergedArrIndex++;
}
the part where I sort the student object by comparing the grade is by converting the char grade into a long with strtol which I think I did good so it might not be a problem.
My problems is that I initialize my array of structs like the following:
struct Student students[5501];
and when I get a new input of the user I just add it into the array like the following:
struct Student aStudent;
int lineCounter = 0;
students[lineCounter] = aStudent;
and increase lineCounter by 1 every time I get a new input. (aStudent is changed when I get a new input)
Here I call the merge-sort function and get weird results:
mergeSort(students, 0, 5501); // 5501 is the size of the array
printArray(students, 5501);
Here is the printArray function created just to see if I get the grade in ascending order
void printArray(struct Student A[], int size)
{
char *p;
int i;
for (i=0; i < size; i++)
printf("%ld", strtol(A[i].grade, &p, 10));
}
but I keep getting that printed:
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
and I don't know why.
Also how can I do that If the user adds 3 students object in the array students
I only treat it as like an array of 3 elements and not an array of 5501 elements ?
Thanks! And sorry if it's a little long I really tried to be concise without having a loss of essential informations.
Since the user can input N numbers of students I recommend you to use a Linked List instead and put the node (struct Student) in his right position depending on the grade.
You can learn more about Linked Lists here.

Malloc Undefined Behavior - Losing data

So, I'm working with some memory bound applications and I have:
1 - Two arrays of structs that simulates tables on a vertical database. One of them just with keys (1.5M 32-bits integer keys) and another one with integer keys and double payloads (150k tuples). The two of then dynamically allocated
2 - An array of 2^15 64-bits unsigned integers
3 - An array of 2^10 32-bits unsigned integers
And I need to allocate dynamically an array of 32-bits integers which I will know the size just on runtime.
The problem is: I've been able to allocate this array using malloc, BUT when I initialize values to zero, it just subscribes the values of the 150k tuples table. Which means, I`m losing data. The worst thing that could happen to a databases researcher.
Allocation of the "tables"
tamCustomer = countLines("customer.tbl");
c_customer = malloc(tamCustomer*sizeof(column_customer));
readCustomerColumn("customer.tbl", c_customer);
tamOrders = countLines("orders.tbl");
c_orders = malloc(tamOrders*sizeof(column_orders));
readOrdersColumn("orders.tbl", c_orders, sel);
Allocation of the problematic array
cht->tamHT = actualPopCounter;
cht->HT = malloc(sizeof(uint32_t)*cht->tamHT);
if (cht->HT == NULL)
printf("deu merda\n");
for (int i=0; i<cht->tamHT; i++)
cht->HT[i] = 0;
So, after this point, half of the table c_customer gets lost, subscribed by zeros.
What can I do to avoid that?
EDIT: structs definitions:
/******** VETOR DE STRUCTS COLUMN CUSTOMER *********/
typedef struct customer_c
{
unsigned int C_CUSTKEY;
float C_ACCTBAL;
} column_customer;
column_customer *c_customer;
/******** VETOR DE STRUCTS COLUMN ORDERS ***********/
typedef struct orders_c
{
unsigned int O_CUSTKEY;
} column_orders;
column_orders *c_orders;
CHT definition:
typedef struct CHT
{
uint64_t bitmap[CHT_BMP_SIZE];
bucket OHT[CHT_OHT_SIZE];
bucket *HT;
uint32_t tamHT;
} CHT;
And thats pretty much the function where it occurs. This is not a small application and Ive been so focused on this problem that I can`t think properly right now (sorry).
inline void generateCHT(column_customer *c_customer, int tamCustomer, CHT * cht)
{
uint32_t ohtOcc=0;
uint32_t chtOcc=0;
uint32_t ohtOccBMP=0;
uint32_t chtOccBMP=0;
uint64_t actualPopCounter;
uint64_t oldPopCounter;
//Allocate CHT
cht->tamHT = 0;
//Initialize OHT and bitmap
for (int i=0; i<CHT_OHT_SIZE;i++)
{
cht->OHT[i]=0;
cht->bitmap[i]=0;
}
for (int i=0; i<tamCustomer; i++)
{
switch (chtInsertBitmap(c_customer[i].C_CUSTKEY, tamCustomer, cht))
{
case 0:
printf("ERROR: Something went wrong while inserting the key %u on the CHT\n", c_customer[i].C_CUSTKEY);
break;
case 1:
chtOccBMP++;
break;
case 2:
ohtOccBMP++;
break;
}
}
//count Population
actualPopCounter = 0;
for (int i=0; i<CHT_BMP_SIZE;i++)
{
oldPopCounter = popCount(cht->bitmap[i]>>32);
cht->bitmap[i] = cht->bitmap[i] | actualPopCounter;
actualPopCounter = actualPopCounter + oldPopCounter;
}
cht->tamHT = actualPopCounter;
cht->HT = malloc(sizeof(uint32_t)*cht->tamHT);
if (cht->HT == NULL)
printf("deu merda\n");
for (int i=0; i<cht->tamHT; i++)
cht->HT[i] = 0;
for (int i=0; i<tamCustomer; i++)
{
if (chtInsertConciseTable(c_customer[i].C_CUSTKEY, cht, tamCustomer) == 0)
ohtOcc++;
else
chtOcc++;
}
printf("OHT has %d occupied buckets and %d on the bitmap \n", ohtOcc, ohtOccBMP);
printf("CHT has %d occupied buckets and %d on the bitmap \n", chtOcc, chtOccBMP);
}
You're possibly walking off the end of the cht->HT array you allocated.
bucket *HT;
...
...
cht->HT = malloc(sizeof(uint32_t)*cht->tamHT);
Try sizeof(bucket) instead.

Allocate memory and generate structures in C

I'm trying to work through Kernighan's book "C Programming Language" to teach myself C in preparation for a data structures class this spring (C is a required prerequisite), but am stuck on how to deal with multiple structures and how you would store multiples to use later for calculations and output. I wrote some code for structures related to student records with variables for id's and scores which follows. The function names and parameters must stay as is and comments describe what should be done by each function.
So here's what I've tried. I thought of just setting up an array of structures for ten students within the allocate function as follows:
struct student s[10];
However, when I try to return it to main and then pass it to the generate function, I get incompatibility errors. My current efforts are below. However, as you can see, my code fails to store anything but the last set of records (i.e. student.id and student.score) generated. Clearly I'm missing a key component and it's preventing me from being able to generate random unique student id's because I can't check a new id against the previous ones. I also can't move forward in writing functions to run calculations on student scores. Any suggestions would be appreciated. Thanks in advance.
#include <stdio.h>
#include<stdlib.h>
#include<math.h>
#include<conio.h>
#include<assert.h>
struct student{
int id;
int score;
};
struct student* allocate(){
/*Allocate memory for ten students*/
struct student* s = malloc(10 * sizeof(struct student));
assert (s != 0);
/*return the pointer*/
return s;
}
void generate(struct student* students){
/*Generate random ID and scores for ten students, ID being between 1 and 10, scores between 0 and 100*/
int i;
for (i = 0; i < 10; i++) {
students -> id = (rand()%10 + 1);
students -> score = (rand()%(100 - 0 + 1) + 0);
printf("%d, %d\n", (*students).id, (*students).score);
}
}
void deallocate(struct student* stud){
/*Deallocate memory from stud*/
free(stud);
}
int main(){
struct student* stud = NULL;
/*call allocate*/
stud = allocate();
/*call generate*/
generate(stud);
/*call deallocate*/
deallocate(stud);
return 0;
}
Your generate() function only ever accesses the first student structure in your array. You need to use that for loop index in there:
for (i = 0; i < 10; i++)
{
students[i].id = (rand()%10 + 1);
students[i].score = (rand()%(100 - 0 + 1) + 0);
printf("%d, %d\n", students[i].id, students[i].score);
}
Change generate to
void generate(struct student* students){
/*Generate random ID and scores for ten students, ID being between 1 and 10, scores between 0 and 100*/
int i;
for (i = 0; i < 10; i++) {
students[i].id = (rand()%10 + 1);
students[i].score = (rand()%(100 - 0 + 1) + 0);
printf("%d, %d\n", students[i].id, students[i].score);
}
}

Struct Array initialization in c

typedef struct _set{
int root;
int rank;
}Set;
void Kruskal(Graph* g)
{
Set uni[g->nv];
Edge result[g->nv - 1];
int i;
int count = 0;
int num = 0;
int aRoot, bRoot;
for(i = 0; i < g->nv; i++){
uni[i].root = i;
uni[i].rank = 0;
}
QuickSort(g, 0, g->ne-1);
while(count != (g->nv-1) && num != g->ne){
WeightedUnion(uni, g->path[num].src, g->path[num].dest);
aRoot = Find(uni, g->path[num].src);
bRoot = Find(uni, g->path[num].dest);
if( aRoot != bRoot){
result[num] = g->path[num];
count++;
}
num++;
}
if(count != g->nv-1){
printf("No spanning tree\n");
}
else{
for(i = 0; i <= count; i++){
printf("[%d] %d - %d : %d\n",i+1,result[i].src,result[i].dest,result[i].weight);
}
}
}
This is my part of code. The problem is that I can't initialize 'uni[g->nv]'. You can see 'for' loop next to the variable area. And I was sure about that reputation must initialize this array but a result was not. That array didn't include any other values. just empty. I cannot find my problem. Please tell me my problem or mistakes.
I run my code in Xcode. Maybe this information is helpful
You are using a variable length array (VLA), that is an array with a length that depends dynamically on an expression during run time. Since the size is not known at compile time, you can't initialize them with an initializer expression, but must do it with a for loop as you are doing.
VLA are usually realized when your program executes on the so-called stack of the function in which it is defined. That stack has a size limit and you have to be careful that you don't overrun it. (And if you do, there is no tool to know directly.)
So don't use VLA as you do for big data of unknown size. Instead, use a pointer and malloc to allocate the memory that you need.

Resources