Inserting in an array struct(Dictionary) in C - c

So created a Dictionary that had a key and an element. It is ordered by the Key field and the space allocated to the Dictionary must always be equal to the number of elements that it contains. So this is what i did:
//Creating a Dictionary structure
typedef struct dict{
int elem;
int key;
}Dictionary;
int main(){
Dictionary * d = NULL;
int dim = 0;
insert(&d, 5, 3, &dim);
insert(&d, 10, 2, &dim);
insert(&d, 6, 1, &dim);
//insert(&d, 9, 6, &dim);
//insert(&d, 55, 2, &dim);
//insert(&d, 11, 5, &dim);
return 0;
}
void insert(Dictionary **d, int elem, int key, int *dim){
(*d) =(Dictionary *)realloc((*d),(*dim)++);//adding space for another element
int i = 0, j = 0;
while(i < (*dim) && (*d)[i].key < key)//searching for the corect position to insert
i++;
//sliding all the lements to the right
for(j = (*dim); j > i; j--){
(*d)[j] = (*d)[j - 1];
}
//iserting the element in the correct position
(*d)[i].elem = elem;
(*d)[i].key = key;
}
So the code works as it should for the first three elements that insert the problem is that whenerver i try to insert the forth i get a stall like an infinte loop and five or more inserts crashes the program. So could someone explain to me what i am missing or what i am doing wrong ?

with (*d) =(Dictionary *)realloc((*d),(*dim)++); you don't allocate enough memory for the next elements.
After a while you end up corrupt some unallocated/unowned memory and it crashes.
You have to take into account the size of your struct (which must be incremented before calling realloc BTW, another fatal mistake). Since I got tricked by that, I don't propose pre-incrementation, but 2 lines:
(*dim)++;
(*d) = realloc((*d),sizeof(Dictionary)*(*dim));
notes:
you never have to cast the output of realloc, malloc, calloc
reallocating at eah step is easy but not optimal. You should forward allocate more than 1 slot, and reallocate only when your reserve is exhausted. That would avoid calling realloc too often and/or moving the memory around when the block is too small too often.

Related

Unable to understand the code

I was trying to make a code to find duplicates in an array and print them. I can't understand this code and why the Calloc is being used and the int main part isn't clear to me.
#include<stdio.h>
#include<stdlib.h>
void printRepeating(int arr[], int size)
{
int *count = (int *)calloc(sizeof(int), (size - 2));
int i;
printf(" Repeating elements are ");
for(i = 0; i < size; i++)
{
if(count[arr[i]] == 1)
printf(" %d ", arr[i]);
else
count[arr[i]]++;
}
}
int main()
{
int arr[] = {4, 2, 4, 5, 2, 3, 1};
int arr_size = sizeof(arr)/sizeof(arr[0]);
printRepeating(arr, arr_size);
getchar();
return 0;
}
The code is actually "dangerous", as it relies on some conditions to hold, e.g. that the maximum integer value in the array is not larger than size-2. So, if your input were, for example, int arr[] = { 114, 112, 114, 5, 2, 3, 1}, then arr[0] would be 114, and the code count[arr[0]]++ would exceed the bounds of the array allocated in printRepeating, which were just 5 elements.
I'd throw the code away and write your own; almost regardless on your experience, your code is likely not worse than the proposed one :-)
The reason for using calloc is that the size isn't known in advance. An alternative would be to use VLA but apparently the author preferred dynamic memory allocation. Kind of bad as the author forgot to free the memory. So this code leaks memory.
Besides that the code is very error prone as it relies on some specific rules for the input (e.g. that no input value is greater that size-2). So my advice is to through this code away and start all over.
BTW: The code uses calloc instead of malloc to get the memory zero initialized.
Regarding main.... This line:
int arr_size = sizeof(arr)/sizeof(arr[0]);
calculates the number of elements in the array.
sizeof(arr) is likely to return 28
sizeof(arr[0]) is likely to return 4
So
28/4 = 7 which is the number of array elements.
This code is really wrong, you shouldn't use it at all.
To give you some hints, this line creates an array:
int *count = (int *)calloc(sizeof(int), (size - 2));
Similar to:
int count[size - 2] // If size was a constant
An unfortunate issue is that the function never disposes the dynamically created array, so you'll see a memory leak.
Line count[arr[i]]++ is a disaster: if the value of arr[i] is greater than size-2 then the software will write to an unassigned memory.
To show how it should be done:
// No value should exceed 50
#define MAX_ARR 50
void printRepeating(int arr[], int size)
{
int found[MAX_ARR];
int i;
// Set found variable to 0
memset(found, 0, sizeof(found));
for(i = 0; i < size; i++)
{
// Did we find the same number before?
if (found[arr[i]] == 1) {
// Yes, print it
printf(" %d ", arr[i]);
} else {
// No, mark is as found
found[arr[i]] = 1;
}
}
}
Actually we use malloc( ) for allocating a single block of specified size that returns a pointer of type of void. This means that we can assign it to any type of type. Form is:
ptr = ( cast - type*) malloc(byte-size)
One very significant difference in malloc() and calloc() is :
While malloc() allocates a single block of storage space with garbage (or random) values, calloc() allocates allocates multiple blocks of storage, each of the same size, and then sets all bytes to zero.

Iterating through an array w/ pointer

So I'm a beginner with C programming and understanding pointers and how to use them is still giving me some trouble. Here I'm simply trying to iterate through an array using a pointer. I've got this bit of code below but instead of ending at 55, it prints an additional value (32765). First, could someone explain to me why I'm getting an extra value? Second, could someone tell me how to limit this program to the values in the array? I tried using *pntr < 5 for the condition but then nothing prints.
void iterate(int* li) {
for (int *pntr = li; *pntr; pntr++) {
printf("%d\n", *pntr);
}
}
int main(){
int values[] = {11, 22, 33, 44, 55};
iterate(values);
}
This is the right code
void walk(const int *arr, size_t n)
{
int *p;
for (p = arr; p < arr + n; ++p)
printf("%d\n", *p);
}
This is because arr + n gets the address of n integers from the base address of arr.
In addition, int arrays aren't null terminated; only char arrays are when they are used with quotation marks.("abc" rather than {'a', 'b', 'c'}).
This for loop:
for (int *pntr = li; *pntr; pntr++) {
printf("%d\n", *pntr);
}
...expects the array to be zero-terminated. By using *pntr as your test, you're testing that the value pointed to by pntr is not zero. As such, if the array doesn't end with a zero, your loop will wander off past the end of the array until it happens to hit a zero or causes a segfault.
your code is overall not bad, but it's missing one major factor: a working end condition.
In your for loop, when you write *pntr, the end condition will be that the loop will halt when reaching a pointed value of 0. But as your array contains non-zero values, it will get one beyond the allocated memory for your array.
Luckily for you, you only see one extra value, but you might see a lot more values.
To fix the missing end conditions, you have two solutions: either you share the array's length with your iterate function, or you add a value that's known to be the final value of your array.
So either you do:
void iterate(const int *arr, size_t n) {
for (it = arr; it < arr+n ; +=it) printf("$d\n", *it);
}
or you can do:
#define LAST_ITEM -1
int values[] = {11, 22, 33, 44, 55, LAST_ITEM};
void iterate(const int *arr, size_t n) {
for (it = arr; *it != LAST_ITEM ; +=it) printf("$d\n", *it);
}
(you could use #define LAST_ITEM 0, as long as you use a value that's not likely to happen in your array).
Out of these two solutions, the best one is to consider your array with its size.

Array that points to another array

I'm new to C.
Create an array which holds at every index a pointer to another array of dynamic size.
int main()
{
unsigned int i , j;
int* array1[2];
int a1[] = {1,2,3};
int a2[] = {2,3};
array1[0] = a1;
array1[1] = a2;
for (i=0 ; i < 2; i++) {
printf(" the value of array1[%d] = %d" , i , *array1[i]);
}
return 1;
}
the value of array1[0] = 1
the value of array1[1] = 2
Only first elements are getting printed . How to print the whole array the index points to. What thing i'm missing.
EDITED ::
I now understand the use but similarly doing it directly , causing an array.
`unsigned int* c[3];
c[0] = {0, 5, 4, 7}; // This Line Err`
c[1] = {0, 5, 4, 3, 2, 6, 7};
c[2] = {0, 5, 4, 3, 2};
Causing an error : file try.c line xx function main: syntax error before `{'
Why ??
Thanks
As you know, array1[0] holds a pointer to the first element of a1 array; to print all elements of a1 array, you should iterate over it, something like this:
for (int i = 0; i < 2; i++){
printf(" the value of a1[%d] = %d", i, *(array1[0] + i);
}
An array is decayed to a pointer in C, in particular when passing it as argument (or storing it in a pointer).
What you are missing is that at runtime, the actual size of the array is not kept (and sizeof is a compile-time operator, replaced by the compiler by a constant - except for VLAs).
You might wish to keep the array size and its content together. Using a struct with a last flexible array member is a cute way to do that:
struct vect_st { unsigned size; int flexarr[]; };
struct vect_st* arr1[2];
Such structures need to be heap allocated (because you know their real size only at runtime):
arr1[0] = malloc(sizeof(struct (vect_st) + 2*sizeof(int));
if (!arr1[0]) {perror("malloc arr1[0]"); exit(EXIT_FAILURE); };
arr1[0]->size = 2;
arr1[0]->flexarr[0] = 4;
arr1[0]->flexarr[1] = 17;
arr1[1] = malloc(sizeof(struct (vect_st) + 3*sizeof(int));
if (!arr1[1]) {perror("malloc arr1[1]"); exit(EXIT_FAILURE); };
arr1[1]->size = 3;
arr1[1]->flexarr[0] = 5;
arr1[1]->flexarr[1] = 6;
arr1[1]->flexarr[2] = 7;
OF course, you should release the memory when you don't need it, so you'll probably end your main with code like
free(arr1[0]), arr1[0] = NULL;
free(arr1[1]), arr1[1] = NULL;
Beware of memory leaks, buffer overflows and other undefined behavior. So compile your code with all warnings & debug info (gcc -Wall -Wextra -g) and use valgrind and the gdb debugger.
Notice also that you should usually not declare non-small arrays (or aggregates) as local data (e.g. some local int biglocarr[1000000]; inside your main or some other function), since the call stack is limited in size (typically to a few megabytes, so no more than a few hundred bytes per call frame). Read about stack overflows and avoid them.
You are using *array1[i] , here " * " means pointer and value at array1[i] and i is 0 in first case, so it is pointing to a1 base, i.e. 1 and so on..

function to insert an element in sorted array in C

I am new to C and was writing a function to insert an element to sorted list. But my code does not display the last digit correctly. Though i know there are variety of ways to correct it but i want to know why my code isnt working, here's the code
#include <stdio.h>
int insert(int array[],int val);
int main (void)
{
int arr[5],j;
for (j = 0; j<5; j++)
{
scanf("%d",&arr[j]);
}
insert(arr,2);
for(j = 0;j<6;j++)
printf("%d",arr[j]);
return(0);
}
int insert(int array[],int val)
{
int k,i;
for (k = 0;k<5;k++)
if(val<array[k])
break;
for (i = 4; i>=k;i--)
{
array[i+1] = array[i];
}
array[k] = val;
return(1);
}
You are writing out of the range of the array here:
for (i = 4; i>=k;i--)
{
array[i+1] = array[i];
Where i+1 == 5 and you array has a range of 0 ...
4
Then you try to print the array but you go out of bounds again:
for(j = 0;j<6;j++)
printf("%d",arr[j]);
First make sure your array is large enough.
When you give a static / auto array to a function for insertion of elements, you must give: Address, Valid length, and Buffer Space unless guaranteed large enough.
When giving a dynamically allocated array, you must give pointer and valid length, you might give buffer space or guarantee enough space left to avoid reallocations.
Otherwise, you risk a buffer overrun, and UB means anything may happen, as in your example.
You're trying to make arr[6] out of arr[5] adding one val - it's impossible in C using statically allocated arrays.
To accomplish what you're trying to do you'd need to use dynamical arrays allocation:
int *arr;
int N = 5;
arr = (int *)malloc(N*sizeof(int));
then you use this arr same way as you did with arr[5] for loading data here via scanf.
And later on , while adding extra value to array - you'd need to reallocate your arr to make it bigger (read about malloc/realloc C functions):
arr = (int *)realloc((N+1)*sizeof(int));
Now your arr is of 6 int-s size.
Unfortunately if you don't know array sizes (number of elements) a priori you would need to deal with dynamical memory allocations in C.
Don't forget to release that memory in the end of the main() function:
free(arr);
You have to increase your array size from 5 to 6 as you are inserting one new element in your array, so there should be some space for that.
int arr[6];
you can also find more information in the link below:
https://learndswithvishal.blogspot.com/2020/06/insert-element-in-sorted-array.html

Concatenating 2 arrays without memcpy

Suppose I ve
int *a,*b;
a= malloc(5*sizeof(int));
b= malloc(5*sizeof(int));
and subsequently assign values.
Let a - 1, 2, 3, 4, 5
b - 6, 7, 8, 9, 10
Is there a method to concatenate both these malloced arrays without using further malloc,realloc or memcpy? There shud not be a malloc of 10 locations!
I must be able to get a[8]=9 after executing, without the overhead of moving the arrays.
The language is C
a= malloc(5*sizeof(int));
You only allocated 5 ints to a, so no, you can't do it without some form or memory allocation (malloc / realloc), since a[8] would be illegal to begin with.
I must be able to get a[8]=9 after executing, without the overhead of
moving the arrays
Since since you are working with contiguous memory regions (which you are calling arrays) you will always have some overhead when moving elements around. If you don't need to access elements by their indexes just use linked lists.
If you don't need strict array indexing, you could make a pseudo-linked-list (I know there's a name for this data type but I can't remember it right now):
struct listish {
int *arr
size_t size;
struct listish *next;
};
The "indexing" function would look like this:
int *index(struct listish *list, size_t i)
{
if(list == NULL) return NULL; // index out of bounds
if(i < list->size) return list->arr + i; // return a pointer to the element
else return index(list->next, i - list->size); // not in this array - go to next node
}
The idea is to combine the in-place reordering of a linked list with the contiguous space of an array. In this case, index(list, 4) would return &a[4], and index(list, 5) would return &b[0], simulating continuous indexing without reallocating and moving your entire array - all you need to do is allocate a few small struct listish objects and set them up properly, a task I leave to you.
What you ask can't be done.
You have, maybe, another option.
Just allocate space for 10 values, and make b point to the correct element
int *a = malloc(10 * sizeof *a);
/* error checking missing */
int *b = a + 5;
a[0] = 1; a[1] = 2; a[2] = 3; a[3] = 4; a[4] = 5;
b[0] = 6; b[1] = 7; b[2] = 8; b[3] = 9; b[4] = 10;
printf("a[8] is %d\n", a[8]);

Resources