Storing data into a dynamic array with structs in C - c

I am having issues storing data from a file into my dynamic array. I am aware that what I have now is incorrect but it is just there for the moment. I have a file which on the first line contains the amount of lines of data essentially. The following lines have two integers side by side to represent an ordered pair. I want to store those two integers into a struct, point, that symbolizes an ordered pair. Also, the there is an array with such a struct that is inside of another struct, list , which contains the size of the array, or the amount of data currently stored in the array and a capacity which is the total amount of space in the array.
I want to store the two integers into variables of type int and then store them into a point inside of my array that is in my list struct.
I am getting very confused having two structs and am unsure if this is the correct approach. Any feedback would be welcomed.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
typedef struct
{
int x;
int y;
} point;
typedef struct
{
int size;
int capacity;
point *A;
} list;
// Compute the polar angle in radians formed
// by the line segment that runs from p0 to p
double polarAngle(point p, point p0)
{
return atan2(p.y - p0.y, p.x - p0.x);
}
// Determine the turn direction around the corner
// formed by the points a, b, and c. Return a
// positive number for a left turn and negative
// for a right turn.
double direction(point a, point b, point c)
{
return (b.x - a.x)*(c.y - a.y) - (c.x - a.x)*(b.y - a.y);
}
int whereSmallest(point A[], int begin, int end, point p0)
{
point min = A[begin];
int where = begin;
int n;
for (n = begin + 1; n < end; n++)
if (polarAngle(A[n], p0) < polarAngle(min, p0))
{
min = A[n];
where = n;
}
return where;
}
void selectionSort(point A[], int N, point p0)
{
int n, s;
point temp;
for (n = 0; n < N; n++)
{
s = whereSmallest(A, n, N, p0);
temp = A[n];
A[n] = A[s];
A[s] = temp;
}
}
// Remove the last item from the list
void popBack(list *p)
{
int x;
x = p->size - 1;
p->A[x] = p->A[x + 1];
}
// Return the last item from the list
point getLast(list *p)
{
point value;
value = p->A[p->size];
return value;
}
// Return the next to the last item
point getNextToLast(list *p)
{
point value;
value = p->A[p->size - 1];
return value;
}
int main(int argc, const char *argv[])
{
point p0, P;
FILE *input;
list *p;
int N, n, x, y;
/*Assuming that the first piece of data in the array indicates the amount of numbers in the array then we record this number as a reference.*/
N = 0;
input = fopen("points.txt", "r");
fscanf(input, "%d", &N);
/*Now that we have an exact size requirement for our array we can use that information to create a dynamic array.*/
p = (point*)malloc(N*sizeof(point));
if (p == NULL)//As a safety precaution we want to terminate the program in case the dynamic array could not be successfully created.
return -1;
/*Now we want to collect all of the data from our file and store it in our array.*/
for (n = 0; n < N; n++)
{
fscanf(input, "%d %d", &P.x, &P.y);
p->A[n] = P.x;
p->A[n] = P.y;
}
fclose(input);
free(p);
return 0;
}

First of all, your code cannot be compiled because this
p->A[n] = P.x;
p->A[n] = P.y;
is wrong, it should be
p->A[n].x = P.x;
p->A[n].y = P.y;
because A has type point and you should access the members of the struct in order to assign values to them.
But this is just the begining of the problems, you didn't allocate space for the A pointer, so this will not work.
You need to allocate space for an instance of type list, which is done this way
p = malloc(sizeof(*p));
Then you need to initialize p's members, for which
p->values = malloc(N * sizeof(point));
p->capacity = N;
p->size = 0;
as you see space was allocated for the values member.
Check fscanf() to insure data integrity and avoid undefined behavior, if fscanf() fails you would never know with your code and you potentially access uninitialized variables which leads to Undefined Behavior.
Capture the values scanned from the file in two int variables and copy them to the array only if the where sucessfuly read
for (n = 0 ; ((n < N) && (fscanf(input, "%d%d", &x, &y) == 2)) ; n++)
/* check that the values were read from the file _______^ */
{
/* store them in the array */
p->values[n].x = x;
p->values[n].y = y;
p->size += 1;
}
Check that the file did open.
I suggest the following code
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
typedef struct
{
int x;
int y;
} point;
typedef struct
{
int size;
int capacity;
point *values;
} list;
// Compute the polar angle in radians formed
// by the line segment that runs from p0 to p
double polarAngle(point p, point p0)
{
return atan2(p.y - p0.y, p.x - p0.x);
}
// Determine the turn direction around the corner
// formed by the points a, b, and c. Return a
// positive number for a left turn and negative
// for a right turn.
double direction(point a, point b, point c)
{
return (b.x - a.x)*(c.y - a.y) - (c.x - a.x)*(b.y - a.y);
}
int whereSmallest(point values[], int begin, int end, point p0)
{
point min = values[begin];
int where = begin;
int n;
for (n = begin + 1; n < end; n++)
if (polarAngle(values[n], p0) < polarAngle(min, p0))
{
min = values[n];
where = n;
}
return where;
}
void selectionSort(point values[], int N, point p0)
{
int n, s;
point temp;
for (n = 0; n < N; n++)
{
s = whereSmallest(values, n, N, p0);
temp = values[n];
values[n] = values[s];
values[s] = temp;
}
}
// Remove the last item from the list
void popBack(list *p)
{
int x;
x = p->size - 1;
p->values[x] = p->values[x + 1];
}
// Return the last item from the list
point getLast(list *p)
{
point value;
value = p->values[p->size];
return value;
}
// Return the next to the last item
point getNextToLast(list *p)
{
point value;
value = p->values[p->size - 1];
return value;
}
int main(int argc, const char *argv[])
{
FILE *input;
list *p;
int N, n, x, y;
/*Assuming that the first piece of data in the array indicates the amount of numbers in the array then we record this number as a reference.*/
N = 0;
input = fopen("points.txt", "r");
if (input == NULL)
return -1;
if (fscanf(input, "%d", &N) != 1)
{
fclose(input);
return -1;
}
p = malloc(sizeof(*p));
if (p == NULL)
return -1;
/*Now that we have an exact size requirement for our array we can use that information to create a dynamic array.*/
p->values = malloc(N * sizeof(point));
p->capacity = N;
p->size = 0;
if (p->values == NULL)//As a safety precaution we want to terminate the program in case the dynamic array could not be successfully created.
{
free(p);
fclose(input);
return -1;
}
/*Now we want to collect all of the data from our file and store it in our array.*/
for (n = 0 ; ((n < N) && (fscanf(input, "%d%d", &x, &y) == 2)) ; n++)
{
p->values[n].x = x;
p->values[n].y = y;
p->size += 1;
}
fclose(input);
free(p->values);
free(p);
return 0;
}
As you can see there is another improvement you can do to the code, it's not too important but it would avoid using the N and n variables which are not necessary.
Note: before using a function, try to read throughly it's documentation, that will prevent all sorts of unexpected results, for example fscanf(), will help you understand my fixes more.

The variable p should be list p.
The points array allocation is p.A = (point*)malloc(N*sizeof(point));
In the filling loop, since A[n] is a point you can't assign it the int P.x or P.y. You can directly put values into the A[n] point like that:
for (n = 0; n < N; n++)
{
fscanf(input, "%d %d", &(p.A[n].x), &(p.A[N].y));
}
The size and capacity of the list should be initialized: p.capacity = N; right after succesfull memory allocation and p.capacity = n; after filling the array
And in the end you should call free(p.A) instead of free(p).

Related

Error releasing structure pointer using free

**Hi, technologists. I'm new here. This is my first time to ask questions here. Please forgive me if I have done something wrong. I hope you can be more patient with me. Thank you very much.
I've been studying PointersOnC. And then I had a little trouble writing exercises. The topic is to write a program to achieve matrix multiplication. I defined a structure and named it a matrix. There are variables x and y of type int in the matrix, x and y store the row and column values. The matrix also has a secondary pointer of type int to store the values in the matrix. I define a struct level pointer in the main function and allocate memory through the function. It then allocates the secondary pointer in the structure and stores the value in the secondary pointer. But I had a problem freeing memory. I first release the first level of the second level pointer, then release the second level pointer, and finally release the structure pointer. An error was reported while releasing the structure pointer. **
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct {
int x, y; // Rows and Columns
int** values; // Numbers in the matrix
} matrix;
// Initialization matrix
bool InitMatrix(matrix** m)
{
*m = (matrix*)malloc(sizeof(matrix*));
if (!*m)
return false;
(*m)->x = 0, (*m)->y = 0;
(*m)->values = NULL; // Secondary pointer
return true;
}
// Dynamic memory allocation two-dimensional array
bool mallocTowAry(matrix* m)
{
if (m->x == 0 || m->y == 0)
return false;
m->values = (int**)malloc(sizeof(int*) * m->x);
if (!m->values)
return false;
for (int i = 0; i < m->x; i++)
{
m->values[i] = (int*)malloc(sizeof(int) * m->y);
if (m->values[i] == NULL)
return false;
}
return true;
}
// Store the number of the matrix in the array
void assginTow(matrix* m)
{
for (int i = 0; i < m->x; i++)
{
printf("Please enter the elements in the i-th row, separated by spaces:\n");
for (int j = 0; j < m->y; j++)
scanf("%d", &m->values[i][j]);
}
}
// Initialize the secondary pointer in the structure
bool assginMatrix(matrix* m, int x, int y)
{
m->x = x, m->y = y;
if (!mallocTowAry(m))
return false;
assginTow(m);
return true;
}
// Print matrix
void showMatrix(matrix* m)
{
for (int i = 0; i < m->x; i++)
{
for (int j = 0; j < m->y; j++)
printf("%d ", m->values[i][j]);
printf("\n");
}
}
int main(int argc, char* args[])
{
matrix* m_1;
// Initialize the matrix, but without x and y
if (!InitMatrix(&m_1))
return 1;
int x, y;
printf("Please enter the row and column values, separated by spaces: \n");
// Read in x and y
scanf("%d %d", &x, &y);
if (!assginMatrix(m_1, x, y))
return 2;
showMatrix(m_1);
// Destroy the matrix
DestoryMatrix(&m_1);
return 0;
}

Code on finding non-dominated points not working properly

I am a beginner at programming (and it is not my subject of discipline) and this is my first question here, apologies if I'm not posting it it properly.
I am trying a problem (in C) in which one has to define a structure for a point, take inputs of points from a file to a dynamic array, in which the first line contains the number of points, and the remaining lines contain the coordinates of the points with spaces in between. Then I have to write a function to determine the points which are non-dominated, definitions given :
• A point P1 = ( x1 , y1 ) is dominated by a point P2 = ( x2 , y2 ) if
y2 > y1 and x2 > x1
• A point is non-dominated in a set of points, if no point dominates
it in that set
And another function to determine and print the level of dominance of each point stored in the array formed. I need to print all non-dominated points, and then print level of dominance of all the points.
This is the code that I have written:
#include <stdio.h>
#include <stdlib.h>
#define MAX 20
#define TRUE 1
#define FALSE 0
typedef struct Coordinates{
float xcord;
float ycord;
}POINT;
//globally declaring dynamic array of points
POINT *Array_of_Points;
//globally declaring dynamic array of non-dominated points
POINT *Non_dominated;
//declaring some functions
int dominance(int n);
int Read_File(char filename[]);
void Xmerge(int head, int middle, int tail);
void XmergeSort(int head, int tail);
void level_of_dominance(int a);
int main(){
char Arr[MAX];
int n, i, d;
printf("Enter file name...");
scanf("%s", Arr);
n = Read_File(Arr);
if(!Read_File(Arr)){ //if error occurs
printf("Terminating program with exit code -1\n");
return -1; //terminate program with return value -1
}
//finds non-dominated points and prints them
d = dominance(n);
printf("The non dominated points are:\n");
for(i = 0; i < d; i++){
printf("(%f, %f)", Non_dominated[i].xcord, Non_dominated[i].ycord);
}
//print all points with levels of dominance
level_of_dominance(n);
printf("End of program... Terminating with exit code 0\n");
free(Array_of_Points);
free(Non_dominated);
return 0;
}
//function reads file in required manner
int Read_File(char filename[]){
int n; //to store number of points present in file
int count = 0;
float x, y;
FILE *fptr = fopen(filename, "r"); //opening given file in readable format
if(!fptr) //file handling if pointer returns null
{
printf("The file %s can't be opened.\n", filename);
return FALSE;
}
fscanf(fptr, "%d", &n); //reading first line consisting of number of points
Array_of_Points = (POINT*)malloc(n * sizeof(POINT)); //allocating memory for npoints
//reading points from file and storing them in globally created dynamic array
while((count < n) && (fscanf(fptr, "%f", &x) == TRUE && fscanf(fptr, "%f", &y) == TRUE)){
Array_of_Points[count].xcord = x;
Array_of_Points[count].ycord = y;
++count;
}
return n; //returns number of points
}
int dominance(int n){ //returns number of non-dominated points
/*METHOD TO FIND DOMINANCE:
* First, arranging points in array by sorting, say, x co-ordinates in DESCENDING ORDER...
* using merge sort algorithm for the same
* The first point in this sorted array is automatically a non dominated point,
* as no other point has x coordinate greater than it
* Then, traverse sorted array and keep track of largest y value, initializing first one to max
* While traversing, the point with y value grater than y max is also non dominated,
* and contributes to new y max and so on...
**/
int foo = 0; //keeps track of number of non-dominated points found so far, initialized to zero
int i = 0;
XmergeSort(0, n);
int ymax = Array_of_Points[0].ycord;
//add first element of the array to Non_dominated array and increase foo count
Non_dominated = (POINT*)malloc(sizeof(POINT));
Non_dominated[0] = Array_of_Points[0];
++foo;
for(; foo < n; foo++){
if(Array_of_Points[foo].ycord > ymax){
++i;
Non_dominated = (POINT*)realloc(Non_dominated, (i + 1) * sizeof(POINT));
Non_dominated[i] = Array_of_Points[foo];
}
}
//all non dominated points stored in array
return i;
}
void level_of_dominance(int a){ //returns number of points dominating a point
int i, j, flag = 0;
for(i = a - 1; i >= 0; i--){
for(j = i; j >= 0; j--){
if((Array_of_Points[i].xcord <= Array_of_Points[j].xcord)&&(Array_of_Points[i].ycord <= Array_of_Points[j].ycord)){
++flag;
}
}
printf("(%f, %f) is dominated by %d points.\n", Array_of_Points[i].xcord, Array_of_Points[i].ycord, flag);
flag = 0; //resetting number of points for next point
}
}
void XmergeSort(int head, int tail){
int mid;
if(head < tail){
mid = (head +tail)/2;
XmergeSort(head, mid);
XmergeSort(mid + 1, tail);
Xmerge(head, mid, tail);
}
}
//function to merge 2 halves of array
void Xmerge(int l, int m, int r)
{
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;
/* create temp arrays */
POINT *T1, *T2;
T1 = (POINT*)malloc(n1 * sizeof(POINT));
T2 = (POINT*)malloc(n2 * sizeof(POINT));
/* Copy data to temp arrays L[] and R[] */
for (i = 0; i < n1; i++)
T1[i] = Array_of_Points[l + i];
for (j = 0; j < n2; j++)
T2[j] = Array_of_Points[m + 1+ j];
/* Merge the temp arrays back into arr[l..r]*/
i = 0;
j = 0;
k = l;
while (i < n1 && j < n2)
{
Array_of_Points[k] = ((T1[i].xcord <= T2[j].xcord)?T1[i]:T2[j]);
((T1[i].xcord <= T2[j].xcord)?i++:j++);
k++;
}
/* Copy the remaining elements of L[], if there are any */
while (i < n1)
{
Array_of_Points[k] = T1[i];
i++;
k++;
}
/* Copy the remaining elements of R[], if there are any */
while (j < n2)
{
Array_of_Points[k] = T2[j];
j++;
k++;
}
}
While running this code on online gdb, I am getting a segmentation fault, like this:
Reading symbols from a.out...done.
/usr/share/gdb/gdbinit: No such file or directory.
(gdb) run
Starting program: /home/a.out
Enter file name...inp.dat
Testing... no. of non dominated points = 4
The non dominated points are:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400b82 in level_of_dominance (a=5) at main.c:107
107 if((Array_of_Points[i].xcord <= Array_of_Points[j].xcord)&&(Ar
ray_of_Points[i].ycord <= Array_of_Points[j].ycord)){
(gdb)
The coordinates of non-dominated points aren't being printed here either.
I'm sorry if what I'm asking is stupid, but I hope someone can help me understand what went wrong.
Thanks in advance.
P.S Please let me know if I should edit my question.
EDIT: I had made a bad mistake in line 105 of the code, as pointed out by #JGroven where in place of j--, I had written j++. I have corrected the same above, but my code isn't doing what it should. This is what the debugger is showing:
Reading symbols from a.out...done.
/usr/share/gdb/gdbinit: No such file or directory.
(gdb) run
Starting program: /home/a.out
Enter file name...inp.dat
The non dominated points are:
(0.000000, 0.000000)(2.500000, 7.200000)(4.700000, 5.000000)(5.600000, 9.500000)(9
.000000, 5.900000) is dominated by 0 points.
(5.600000, 9.500000) is dominated by 0 points.
(4.700000, 5.000000) is dominated by 0 points.
(2.500000, 7.200000) is dominated by 0 points.
(0.000000, 0.000000) is dominated by 0 points.
End of program... Terminating with exit code 0
*** Error in `/home/a.out': free(): invalid next size (fast): 0x00000000006034c0 *
**
Program received signal SIGABRT, Aborted.
0x00007ffff7a47c37 in __GI_raise (sig=sig#entry=6)
at ../nptl/sysdeps/unix/sysv/linux/raise.c:56 56 ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or
directory. (gdb)
EDIT 2: As further pointed out by #Hitokiri,j will become -1 if initialized to i - 1, hence I have changed that to i. And also changed the type of the function to find level of dominance into void.
I figured out my mistake with the help of a friend. The dominance function wasn't completely correct, I have made changes there. And there is something not working properly with the merge sort function I have written, which I shall try to figure out shortly. In the meantime I have replaced it with insertion sort. I am posting my corrected code below.
Thanks to everyone for your help.
#include <stdio.h>
#include <stdlib.h>
#define MAX 20
#define TRUE 1
#define FALSE 0
//segmentation fault...
typedef struct Coordinates{
float xcord;
float ycord;
}POINT;
//globally declaring dynamic array of points
POINT *Array_of_Points;
//globally declaring dynamic array of non-dominated points
POINT *Non_dominated;
//declaring some functions
int dominance(int n);
int Read_File(char filename[]);
/*void Xmerge(int head, int middle, int tail);
void XmergeSort(int);*/
void XInsertion(int n);
int level_of_dominance(int a);
int main(){
char Arr[MAX];
int n, i, d;
printf("Enter file name...");
scanf("%s", Arr);
n = Read_File(Arr);
if(!Read_File(Arr)){ //if error occurs
printf("Terminating program with exit code -1\n");
return -1; //terminate program with return value -1
}
//finds non-dominated points and prints them
d = dominance(n);
printf("The non dominated points are:\n");
for(i = 0; i < d; i++){
printf("(%f, %f)", Non_dominated[i].xcord, Non_dominated[i].ycord);
}
printf("\n");
//print all points with levels of dominance
level_of_dominance(n);
printf("End of program... Terminating with exit code 0\n");
free(Array_of_Points);
free(Non_dominated);
return 0;
}
//function reads file in required manner
int Read_File(char filename[]){
int n; //to store number of points present in file
int count = 0;
float x, y;
FILE *fptr = fopen(filename, "r"); //opening given file in readable format
if(!fptr) //file handling if pointer returns null
{
printf("The file %s can't be opened.\n", filename);
return FALSE;
}
fscanf(fptr, "%d", &n); //reading first line consisting of number of points
Array_of_Points = (POINT*)malloc(n * sizeof(POINT)); //allocating memory to store data of n points
//reading points from file and storing them in globally created dynamic array
while((count < n) && (fscanf(fptr, "%f", &x) == TRUE && fscanf(fptr, "%f", &y) == TRUE)){
Array_of_Points[count].xcord = x;
Array_of_Points[count].ycord = y;
++count;
}
return n; //returns number of points
}
int dominance(int n){ //returns number of non-dominated points
/*METHOD TO FIND DOMINANCE:
* First, arranging points in array by sorting, say, x co-ordinates in DESCENDING ORDER...
* using merge sort algorithm for the same
* The first point in this sorted array is automatically a non dominated point,
* as no other point has x coordinate greater than it
* Then, traverse sorted array and keep track of largest y value, initializing first one to max
* While traversing, the point with y value grater than y max is also non dominated,
* and contributes to new y max and so on...
**/
int foo = 0; //keeps track of number of non-dominated points found so far, initialized to zero
int i;
XInsertion(n);
int ymax = Array_of_Points[0].ycord;
//add first element of the array to Non_dominated array and increase foo count
Non_dominated = (POINT*)malloc(sizeof(POINT));
Non_dominated[0] = Array_of_Points[0];
++foo;
for(i=1 ; i < n; i++){ //note change
if(Array_of_Points[i].ycord > ymax){
ymax=Array_of_Points[i].ycord; /*changes made*/
Non_dominated = (POINT*)realloc(Non_dominated, (foo+1) * sizeof(POINT));
Non_dominated[foo] = Array_of_Points[i];
foo++;
}
}
//all non dominated points stored in array
return foo;
}
int level_of_dominance(int a){ //returns number of points dominating a point
int i, j, flag = 0;
for(i = a - 1; i >= 0; i--){
for(j = i - 1; j >= 0; j--){
if((Array_of_Points[i].xcord <= Array_of_Points[j].xcord)&&(Array_of_Points[i].ycord <= Array_of_Points[j].ycord)){
++flag;
}
}
printf("(%f, %f) is dominated by %d points.\n", Array_of_Points[i].xcord, Array_of_Points[i].ycord, flag);
flag = 0; //resetting number of points for next point
}
}
/*
void XmergeSort(int head, int tail){
int mid;
if(head < tail){
mid = (head +tail)/2;
XmergeSort(head, mid);
XmergeSort(mid + 1, tail);
Xmerge(head, mid, tail);
}
}
//function to merge 2 halves of array
void Xmerge(int l, int m, int r)
{
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;
// create temp arrays
POINT *T1, *T2;
T1 = (POINT*)malloc(n1 * sizeof(POINT));
T2 = (POINT*)malloc(n2 * sizeof(POINT));
// Copy data to temp arrays L[] and R[]
for (i = 0; i < n1; i++)
T1[i] = Array_of_Points[l + i];
for (j = 0; j < n2; j++)
T2[j] = Array_of_Points[m + 1+ j];
// Merge the temp arrays back into arr[l..r]
i = 0;
j = 0;
k = l;
while (i < n1 && j < n2)
{
Array_of_Points[k] = ((T1[i].xcord <= T2[j].xcord)?T1[i]:T2[j]);
((T1[i].xcord <= T2[j].xcord)?i++:j++);
k++;
}
// Copy the remaining elements of L[], if there are any
while (i < n1)
{
Array_of_Points[k] = T1[i];
i++;
k++;
}
// Copy the remaining elements of R[], if there are any
while (j < n2)
{
Array_of_Points[k] = T2[j];
j++;
k++;
}
}*/
void XInsertion(int n)
{
int i,j;
POINT a;
//Applying insertion-sort on x co-ordinates to have them arranged in decreasing order
for(i=0;i<n;i++)
{
j=i-1;
a=Array_of_Points[i];
while((Array_of_Points[j].xcord<=a.xcord)&&(j>=0))
{
if(Array_of_Points[j].xcord==a.xcord && Array_of_Points[j].ycord>a.ycord)
break;//in case of tie, arrange in decreasing order
else
{
Array_of_Points[j+1]=Array_of_Points[j];
j--;
}
}
Array_of_Points[j+1]=a;
}
}
And here is the output:
Enter file name...inp.dat
The non dominated points are:
(12.600000, 2.300000)(9.000000, 5.900000)(5.600000, 9.500000)
(2.500000, 7.200000) is dominated by 1 points.
(4.700000, 5.000000) is dominated by 2 points.
(5.600000, 9.500000) is dominated by 0 points.
(9.000000, 5.900000) is dominated by 0 points.
(12.600000, 2.300000) is dominated by 0 points.
End of program... Terminating with exit code 0
Any suggestions and tips to improve my program and techniques for debugging are most welcome.

Optimization of program processing structured input for large data

I have this one task. To make it more clear, I am gonna use picture below as an example. Input and output is separated with dotted line. First line of input is number N - number of sets. For every set, it's first line are 2 numbers - first one declares how many numbers am I gonna process and second one is number of intervals. Second line specifies the numbers to process and third line contains 2 numbers X and Y, which create and interval. For every interval I have to output 3 numbers - lowest number on interval, index of highest number on interval and XOR of all numbers. Everything is running fine except it is really slow for big data and I have no idea how to make work faster. I have attached my code and large data input as well.
input.txt
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int id;
int index;
} Censor;
int Xor(const int x, const int y, const Censor array[]) {
int xor = array[x].id;
if (x == y) {
return xor;
}
for (int i = x + 1; i <= y; i++) {
xor ^= array[i].id;
}
return xor;
}
int int_cmp(const void *a, const void *b) {
const Censor *ia = (const Censor *)a;
const Censor *ib = (const Censor *)b;
return (ia->id - ib->id);
}
int LowestId(const int x, const int y, Censor array[]) {
int id = array[x].id;
if (x == y) {
return id;
}
qsort(array, y - x + 1, sizeof(Censor), int_cmp);
return array[0].id;
}
int HighestIdIndex(const int x, const int y, Censor array[]) {
int index = array[x].index;
if (x == y) {
return index;
}
qsort(array, y - x + 1, sizeof(Censor), int_cmp);
return array[y].index;
}
int main() {
int t, n, q, b, e;
int max = 100;
int count = 0;
int *output = (int *)malloc(max * sizeof(output));
scanf("%d", &t); //number of sets
for (int i = 0; i < t; i++) {
scanf("%d %d", &n, &q);
//I am making 3 separate arrays for numbers, because some of them are being sorted and some of them not
Censor lowest_id[n];
Censor highest_id_index[n];
Censor xor[n];
//This loop fills arrays with the numbers to be processed
for (int j = 0; j < n; j++) {
scanf("%d", &(lowest_id[j].id));
lowest_id[j].index = j;
highest_id_index[j].id = lowest_id[j].id;
highest_id_index[j].index = j;
xor[j].id = lowest_id[j].id;
xor[j].index = j;
}
// Now I am scanning intervals and creating output. Output is being stored in one dynamically allocated array.
for (int k = 0; k < q; k++) {
scanf("%d %d", &b, &e);
if (count + 3 >= max) {
max *=2;
int *tmp = (int *)realloc(output, max * sizeof(tmp));
if (tmp == NULL) {
return 1;
} else {
output = tmp;
}
}
output[count++] = LowestId(b, e, lowest_id);
output[count++] = HighestIdIndex(b, e, highest_id_index);
output[count++] = Xor(b, e, xor);
}
}
printf("---------------------\n");
for (int i = 0; i < count; i++) {
printf("%d\n", output[i]);
}
free(output);
return 0;
}
Thanks #Dan Mašek and #Alex Lop. Sorting subarray in this case was unnecessary. Much easier is to iterate through the subarray in linear complexity.

Increase dynamic array size with a function; free error, invalid next size (fast)

I need to create a dynamic array and put five number, after there is another input which is how much I have to increase the array size.
When all input are ended I am going to increase the array size and put numbers inside.
everything works but free return me this error: "free(): invalid next size (fast): 0x00000..."
I think there are errors inside "extend" function
void extend(int *V, int n, int s)
{
int *pt;
pt = realloc(V, n*sizeof(int));
int i;
pt[5]=s;
for(i=6;i<(5+n);i++)
pt[i] = pt[i-1]*2;
}
int main()
{
int *v;
int n,i, sum;
sum = 0;
v = malloc(sizeof(int)*5);
for(i=0;i<5;i++)
{
scanf("%d", &v[i]);
sum+=v[i];
}
scanf("%d", &n);
extend(v,n,sum);
for(i=0;i<(5+n);i++)
printf("%d\n", v[i]);
free(v);
return 0;
}
The function does not change the original variable v. It should be defined at least like
void extend(int **V, int n, int s)
{
int *pt;
pt = realloc(*V, n*sizeof(int));
if ( pt )
{
int i;
pt[5]=s;
for(i=6; i < n; i++)
pt[i] = pt[i-1]*2;
*V = pt;
}
}
Or
int extend(int **V, int n, int s)
{
int *pt;
pt = realloc(*V, n*sizeof(int));
int success = pt != NULL;
if ( success )
{
int i;
pt[5]=s;
for(i=6; i < n; i++)
pt[i] = pt[i-1]*2;
*V = pt;
}
return success;
}
And the function should be called lije
extend( &v,n,sum);
Take into account that the function is unsafe because in general n can be less than or equal to 5. And this statement
for(i=6;i<(5+n);i++)
^^^^
can result in undefined behavior.
Or the function shall allocate n + 5 elements. For example
pt = realloc(*V, ( n + 5 )*sizeof(int));
^^^^^^^^
Also the using of this magic number 5 is unclear and does not make sense.
Well, in function extend:
You are allocating pt to a memory block of n entries
You are attempting to access pt at indexes beyond n-1
More specifically, with:
pt = realloc(V, n*sizeof(int));
for (i=6; i<(5+n); i++)
pt[i] = ...
You are performing illegal memory-access operations on:
pt[n]
pt[n+1]
pt[n+2]
pt[n+3]
pt[n+4]
The realloc returns a pointer to the new memory block but you do not return that to the caller. Instead v in main, is the same v that was before the call but now invalid and which causes your error no doubt, easiest is to return pt instead:
int* extend(int *V, int n, int s)
{
int *pt;
pt = realloc(V, n*sizeof(int));
int i;
pt[5]=s;
for(i=6;i<(5+n);i++)
pt[i] = pt[i-1]*2;
return pt;
}
...
v = extend(v,n,sum);
another thing that is not correct is your initialization of the new elements, n should contain the number of new elements plus any old since you want the allocated the block to be bigger. better to give old and new number of elements to it:
int* extend(int *V, int oldNumber, int newNumber, int s)
{
int *pt = realloc(V, newNumber*sizeof(int));
int i;
if (pt==NULL)
{
fprintf(stderr,"Out of memory\n");
return V;
}
pt[oldNumber]=s;
// now you can initialize the rest of the array
for(i=oldNumber+1;i<newNumber;i++)
pt[i] = pt[i-1]*2;
return pt;
}
...
v = extend(v,5,n,sum);
Grow an array like this
int capacity = 10; // don't start off as tiny
ENTRY *array = malloc(capacity * sizeof(ENTRY));
int N = 0; //number of entries.
To add
int addentry(ENTRY *entry)
{
ENTRY *temp;
if(N >= capacity)
{
temp = realloc(array, (capacity + capacity/2) * sizeof(ENTRY));
if(!temp)
goto out_of_memory;
array = temp;
capacity = capacity + capacity/2;
}
array[N] = *entry;
N++;
return 0;
out_of_memory:
//always a problem, maybe terminate program here
// as it is, just shunt up
return -1;
}
You need the temp because realloc returns 0 on failure but keeps
the argument intact, so you need to keep array to destroy it
gracefully. Grow by about 1.5, doubling is too aggressive and
reallocating on every call is too expensive.

An array that increases in size as a loop continues C

I'm trying to generate an array that increases in size as a while loop iterates. I know a pointer has something to do with the solution. Please look at the code below.
#include <stdio.h>
int main () {
int x = 0;
int *F = malloc(sizeof(int)); //I want F to start out as :-
F[0] = 1; // 1 by 1
F[1] = 2; // 1 by 2 such that it increases in size when assigned
int now = 2;
int evenSum = 2;
while (x <= 40000) {
F[now] = F[now-1] + F[now-2];
x = F[now];
if (F[now] % 2)
{
evenSum += F[now];
}
++now;
}
printf("The outcome is %d\n", evenSum);
//free(F);
// Yes this is problem 2 of euler challenge, i already got a working static model
}
Many Thanks in Advance
EDIT
What I'm actually looking for is the sum of all the even fib's up to a cut off limit of 40M. I could (what i did first time) sum the even numbers as i encounter them during the fib sequence. This meant i did not keep a array of some arbitary size. The purpose of this post is to create a growing memory that just keeps on consuming memory until it gets to the answer.
The following is the code I got from the brilliant answer that was given.
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
struct vector {
size_t size;
int *data;
};
void vector_resize(struct vector *vector, size_t size) {
if (vector->size >= size)
return;
while (vector->size < size)
vector->size *= 2;
vector->data = realloc(vector->data, sizeof(int) * vector->size);
assert(vector->data != NULL);
}
struct vector * vector_init() {
struct vector *vector = malloc(sizeof(*vector));
vector->size = 4;
vector->data = malloc(vector->size * sizeof(int));
return vector;
}
void vector_free(struct vector *vector) {
free(vector->data);
free(vector);
}
void vector_put(struct vector *vector, size_t index, int data) {
vector_resize(vector, index+1);
vector->data[index] = data;;
}
int vector_get(struct vector *vector, size_t index) {
vector_resize(vector, index+1);
return vector->data[index];
}
int main() {
struct vector *vector = vector_init();
int fibNow = 0;
int now = 2;
vector_put(vector, 0, 1);
vector_put(vector, 1, 2);
int evenSum = 2;
while (fibNow <= 4000000) {
fibNow = vector_get(vector, (now-1)) + vector_get(vector, (now-2));
vector_put(vector, now, fibNow);
if (fibNow % 2 == 0) {
evenSum += fibNow;
}
++now;
}
printf("The outcome is %d\n", evenSum);
// vector_put(vector, 0, 5);
// vector_put(vector, 9, 2);
// int i;
// for (i=0; i<10; ++i)
// printf("index 0: %d\n", vector_get(vector, i));
vector_free(vector);
}
So, In C we aren't allowed to overload the operator[]. But we could still create an object that functions like your request:
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
struct vector {
size_t size;
int *data;
};
void vector_resize(struct vector *vector, size_t size) {
if (vector->size >= size)
return;
while (vector->size < size)
vector->size *= 2;
vector->data = realloc(vector->data, sizeof(int) * vector->size);
assert(vector->data != NULL);
}
struct vector * vector_init() {
struct vector *vector = malloc(sizeof(*vector));
vector->size = 4;
vector->data = malloc(vector->size * sizeof(int));
return vector;
}
void vector_free(struct vector *vector) {
free(vector->data);
free(vector);
}
void vector_put(struct vector *vector, size_t index, int data) {
vector_resize(vector, index+1);
vector->data[index] = data;;
}
int vector_get(struct vector *vector, size_t index) {
vector_resize(vector, index+1);
return vector->data[index];
}
int main() {
struct vector *vector = vector_init();
vector_put(vector, 0, 5);
vector_put(vector, 9, 2);
for (int i=0; i<10; ++i)
printf("index 0: %d\n", vector_get(vector, i));
vector_free(vector);
}
Additionally, it's fun to look at a C++ version of what this could be. C++ makes this look far more like your original code, because we can overload operator[] for arbitrary objects.
#include <cstdio>
#include <vector>
template <typename T>
class auto_growing_vector {
private:
std::vector<T> data;
public:
T & operator[](size_t index) {
if (index >= data.size())
data.resize(index + 1);
return data[index];
}
};
int main() {
auto_growing_vector<int> vector;
vector[0] = 5;
vector[9] = 2;
for (int i=0; i<10; ++i)
printf("index 0: %d\n", vector[i]);
}
In general, realloc should do the trick for you. Example (this is just a snippet - you will need to do the rest yourself):
int *F;
F = malloc(2 * sizeof *F); // note you have to start with 2 elements for your code, not 1
F[0] = 1;
F[1] = 2;
// when you know you need to increase the size of F:
temp = realloc(F, n * sizeof *F); // where n is the new size in elements
if(temp != NULL) F = temp; // note that the block may have moved to a new place!
else {
printf("unable to grow the array to %d elements!\n", n);
free(F);
exit(0);
}
Of course for this problem you don't need to keep all the Fibonacci numbers - just the last two. This actually suggests a much simpler code. Let me start if for you, and see if you can finish it (since you are doing the Euler problems, which are all about figuring it out for yourself):
int first = 1;
int second = 1; // usually you start with 1,1,2,3,...
int temp, current;
int count;
int N = 4000; // where we stop
for(count = 2; count < N; count ++) {
current = first + second;
first = second;
second = current;
}
If you look closely, you can get even more efficient that this (hint, you really only need to keep one older value, not two...)
Reading the comments, if you want all the numbers in memory, you should just allocate enough space from the outset:
F = malloc(4000 * sizeof *F);
and no further manipulations are needed. Make sure your last index is 3999 in that case (since arrays are zero indexed).
I One way would be to use 2D array int[n][n], whith a lot of unused space
II Easier way would be to expend array size in every iteration by realocate function.
Just in that case, either:
a) every element of the original array would be a pointer to a new array of length i (i beeing iteration number), you would then realocate the original array to make size for new pointer, then allocate i*sizeof(int) of new memory for that new array that pointer would point to.
b) You would make linearized traingular matrix in which the original array will hold just numbers, not pointers. In every iteration you would expand it's size for i new elements. Linearized trangular matrix is a onedimensional array of numbers in which data is saved like this:
ordinary matrix: (/ = wasted memory)
A///
BC//
DEF/
GHIJ
linarized triangular matrix
ABCDEFGHIJ
You can acces linerized triangular matrix element E with coordinates [y,x] = [2,1] (element 'A' taken for origin) like
sum=0;
for(iy=0;iy<y;iy++)
for(ix=0;ix<=y && ix<x;ix++) sum++;
//myLinMatr[sum]=='E'

Resources