I am trying to implement a vector or arraylist in C. The code does not have a main, so I am compiling it with gcc -c file.c . I have two questions, the first being how to implement an insert function for the arraylist, and the second being why I receive the error that list-> is not a function.
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
typedef struct ArrayList {
int *data;
int capacity;
int size;
ArrayList *list;
ArrayList ArrayList_init(int);
int insert(ArrayList *, int , int);
int set(ArrayList*, int, int);
int destroy(ArrayList *);
int print(ArrayList *);
int append(ArrayList *, int);
int valueOf( ArrayList *, int);
int size(ArrayList *);
int capacity(ArrayList *);
} ArrayList;
ArrayList * ArrayList_Init( int n )
{
ArrayList->data = malloc(sizeof(n) * ArrayList->capacity);
}
int append( ArrayList * list, int val )
{
if (list->size >= list->capacity)
return 1;
else
Arraylist->data[list->size++] = value;
return 0;
}
int print( ArrayList * list )
{
printf("%d\n", list->data);
return 0;
}
int set( ArrayList * list, int val, int index )
{
while(index >= list->size)
append(ArrayList, 0);
return 0;
if (index < 0 || index >= size)
return 1;
}
int destroy( ArrayList * list )
{
free(list->data);
return 0;
}
int insert(ArrayList * list, int val, int index)
{
return 0;
}
int valueOf( ArrayList * list, int element )
{
int x;
x = list->data[element];
return x;
}
int size(ArrayList * list)
{
return list->size;
}
int capacity(ArrayList * list)
{
return list->capacity;
}
int main(void)
{
int n = 3;
int i;
int stat; // Error code
int size;
int val = 0;
int capacity;
// allocate list
ArrayList *list = NULL;
list = ArrayList_Init(n);
printf("ArrayList initialized to %d elements\n", n);
printf("Size of List = %d\n", list->size(list));
printf("Capacity of List = %d\n", list->capacity(list));
// Fill initial values
list->set(list, val++, 0);
list->set(list, val++, 1);
list->set(list, val++, 2);
}
Thank you
First of all if you declare a function that returns something it must do so.
I think your ArrayList_Init should more look like this (I am assuming you want to store integers)
ArrayList * ArrayList_Init( int n )
{
ArrayList * list = malloc(ArrayList);
list->data = malloc(sizeof(int) * n);
list->capacity = n;
list->size=0;
return list;
}
In append as well as in Init you are trying to access a type.
Arraylist->data[list->size++] = value;
but it is supposed to be
list->data[list->size++] = value;
For your insert you can do something similiar to the following:
int insert( ArrayList * list, int val ,int position)
{
if (list->size >= list->capacity){
int * temp = malloc(sizeof(int) * list->capacity *2);
int i;
for(i=0;i<position-1;i++){
temp[i]=list->data[i];
}
for(i=postion-1;i<list->size;i++){
temp[i+1]=list->data[i];
}
free(list->data);
list->data=temp;
list->capacity *=2;
}else{
for(i=list->size;i>postion-1;i--){
list->data[i]=list->data[i-1];
}
}
list->data[position-1]=val;
list->size++;
return 1;
}
You probably want to do something similar in append because otherwise you just have a static array. The idea of a vector is that it grows and shrinks automatically.
Edit:
In C you cannot just declare a prototype of a function inside a struct and than access it.
The only way you can do something similar to what you want to do is by storing a pointer to each of the functions inside your struct. Have a look at the following post.
Define functions in structs
Related
I have some structs as following:
typedef struct {
char debutAge[15];
char finAge[15];
} Age;
typedef struct {
char type[15];
char composants[50];
Age utilisation;
} Categorie;
typedef struct {
int code;
char nom[30];
float prix;
Categorie med;
int quantitie;
} Medicament;
#define MAX 100
typedef Medicament Pharmacie[MAX];
Pharmacie P;
int nb=0;
In my main function, I'm trying to add a new element to the Pharmacie P array, this is what I tried:
void main()
{
Medicament m = Saisir();
ajouterMedicament(P, nb, m);
afficherMedicaments();
}
int ajouterMedicament(Pharmacie *ph, int *nb, Medicament m) {
int i;
for (i = 0; i < *nb; i++) {
if (m.code == ph[i].code) {
ph[i].prix = m.prix;
ph[i].quantitie = m.quantitie;
}
return 1;
}
if (*nb < MAX) {
ph[*nb] = m;
*nb += 1;
return 1;
}
return 0;
}
But I'm getting an error on this line: mif (m.code == ph[i].code) { :
expression must have struct or union type
How can I solve this ?
You don't need to declare the first argument as Pharmacie *. Pharmacie is a typedef for an array, so you don't need to add *.
int ajouterMedicament(Pharmacie ph, int *nb, Medicament m) {
And in the call, you need to pass a pointer to nb so it can be updated:
ajouterMedicament(P, &nb, m);
In general it gets confusing when you use typedef for pointer types, and you ran into that. I recommend not doing that. See Is it a good idea to typedef pointers?
This question already has answers here:
Crash or "segmentation fault" when data is copied/scanned/read to an uninitialized pointer
(5 answers)
Closed 2 years ago.
Background context:
I was doing leetcode twoSum and trying to understand one of the solutions. So, I decided to implement the solutions in the code block and use the debugger.
#include <stdio.h>
#include <stdlib.h>
#define SIZE 50000
int hash(int key);
void insert(int *keys, int *values, int key, int value);
int search(int *keys, int *values, int key);
int* twoSum(int* nums, int numsSize, int target, int* returnSize);
int main()
{
int ar[4]={2,7,11,15};
int *ans;
int *returnSize;
ans=malloc(2*sizeof(int));
ans=twoSum(ar,4,9,returnSize);
printf("d d ",ans[0],ans[1]);
free(ans);
return 0;
}
int hash(int key) {
int r = key % SIZE;
return r < 0 ? r + SIZE : r;
}
void insert(int *keys, int *values, int key, int value) {
int index = hash(key);
while (values[index]) {
index = (index + 1) % SIZE;
}
keys[index] = key;
values[index] = value;
}
int search(int *keys, int *values, int key) {
int index = hash(key);
while (values[index]) {
if (keys[index] == key) {
return values[index];
}
index = (index + 1) % SIZE;
}
return 0;
}
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
*returnSize = 2;
int keys[SIZE]; //new array
int values[SIZE] = {0}; //new array
for (int i = 0; i < numsSize; i++) {
int complements = target - nums[i];
// check for complements in the hash table
int value = search(keys, values, complements);
if (value) {
//return an array
int *indices = (int *) malloc(sizeof(int) * 2);
indices[0] = value - 1;
indices[1] = i;
return indices;
}
//if not insert the current values
insert(keys, values, nums[i], i +1);
}
return NULL;
}
When I use the debugger, the error SEGMENTATION fault appears at line *returnSize=2?
What is the problem?
I was trying to understand why i+1 in insert(keys, values, nums[i], i +1) instead of i?
You need to initialize returnSize before you can dereference it. You've got UB because you dereference a pointer that is not initialized. But I suspect what you really wanted was to have returnSize as an output parameter, which would look like this:
int main()
{
int ar[4]={2,7,11,15};
int *ans;
int returnSize;
ans=malloc(2*sizeof(int));
ans=twoSum(ar,4,9, &returnSize);
printf("d d ",ans[0],ans[1]);
free(ans);
return 0;
}
Note that returnSize in main() is now of type int (not int*). Its address is passed to the function twoSum. The difference is that the pointer passed to the function points to an existing variable.
I'm working for this ADT project and i need to implement the insertion sort algorithm and verify that it works fine in an appropriate test function, that apply the algorithm to an array of double, a string and a struct.
I'm using as a guideline this pseudocode:
procedure InsertionSort(a, n)
for i <- 1, (n-1) do
j <- 1
while (j>0) and (a[j] < a[j-1]) do
Swap(a, j-1, j)
end while
end for
end procedure
I can't understand what the problem is.
The test function gives me error on the first assert () [ in test_sort_algorithm(...) ], therefore telling me that the algorithm is not working properly. But I can't understand where the error is. I've tried to recreate the algorithm for a normal array, without using a void pointer, and everything works. So I guess my problem is that I didn't understand the use of void pointers.
Can anyone please help me understand what's wrong with my Insertion sort algorithm?
Thank you.
This is my attempt:
/**
* \brief Sorts the given array according to the insertion sort algorithm.
*
* \param base Pointer to the start of the input array.
* \param n Number of elements in the input array.
* \param size The size (in bytes) of each element of the array.
* \param cmp Pointer to the comparison function used to sort the array in
* ascending order.
* The comparison function is called with two arguments that point to the
* objects being compared and must return an interger less than, equal to, or
* greater than zero if the first argument is considered to be respectively
* less than, equal to, or greater than the second.
*/
void upo_insertion_sort(void *base, size_t n, size_t size, upo_sort_comparator_t cmp)
{
size_t i, j;
unsigned char *ptr = base;
for (i = 1; i <= n-1; i++)
{
j = i;
while ( (j > 0) && (cmp(ptr+j*size, ptr+(j-1)*size) < 0) )
{
swap(ptr+(j-1)*size, ptr+j*size, size);
j = j - 1;
}
}
}
void swap(void *a, void *b, size_t n)
{
void *tmp = malloc(n);
if (tmp == NULL) { abort(); }
memmove(tmp, a, n);
memmove(a, b, n);
memmove(b, tmp, n);
free(tmp);
}
upo_sort_comparator_t cmp is a pointer to a comparison function. Declaration:
/** \brief Type definition for comparison functions used to compare two elements */
typedef int (*upo_sort_comparator_t)(const void*, const void*);
As I say before this function must be tested, to see if the algorithm work properly.
Code:
#define N 9
struct item_s
{
long id;
char *name;
};
typedef struct item_s item_t;
static double da[] = {3.0,1.3,0.4,7.8,13.2,-1.1,6.0,-3.2,78};
static double expect_da[] = {-3.2,-1.1,0.4,1.3,3.0,6.0,7.8,13.2,78.0};
static const char *sa[] = {"The","quick","brown","fox","jumps","over","the","lazy","dog"};
static const char *expect_sa[] = {"The","brown","dog","fox","jumps","lazy","over","quick","the"};
static item_t ca[] = {{9,"john"},{8,"jane"},{7,"mary"},{6,"anthony"},{5,"stevie"},{4,"bob"},{3,"ann"},{2,"claire"},{1,"alice"}};
static item_t expect_ca[] = {{1,"alice"},{2,"claire"},{3,"ann"},{4,"bob"},{5,"stevie"},{6,"anthony"},{7,"mary"},{8,"jane"},{9,"john"}};
/* Comparators */
static int double_comparator(const void *a, const void *b);
static int string_comparator(const void *a, const void *b);
static int item_comparator(const void *a, const void *b);
/* Test cases */
void test_sort_algorithm(void (*sort)(void*,size_t,size_t,upo_sort_comparator_t));
static void test_insertion_sort();
int double_comparator(const void *a, const void *b)
{
const double *aa = a;
const double *bb = b;
return (*aa > *bb) - (*aa < *bb);
}
int string_comparator(const void *a, const void *b)
{
const char **aa = (const char**) a;
const char **bb = (const char**) b;
return strcmp(*aa, *bb);
}
int item_comparator(const void *a, const void *b)
{
const item_t *aa = a;
const item_t *bb = b;
return (aa->id > bb->id) - (aa->id < bb->id);
}
void test_sort_algorithm(void (*sort)(void*,size_t,size_t,upo_sort_comparator_t))
{
int ok = 1;
size_t i = 0;
double *da_clone = NULL;
char **sa_clone = NULL;
item_t *ca_clone = NULL;
ok = 1;
da_clone = malloc(N*sizeof(double));
assert( da_clone != NULL );
memcpy(da_clone, da, N*sizeof(double));
sort(da_clone, N, sizeof(double), double_comparator);
for (i = 0; i < N; ++i)
{
ok &= !double_comparator(&da_clone[i], &expect_da[i]);
}
free(da_clone);
assert( ok );
ok = 1;
sa_clone = malloc(N*sizeof(char*));
assert( sa_clone != NULL );
memcpy(sa_clone, sa, N*sizeof(char*));
sort(sa_clone, N, sizeof(char*), string_comparator);
for (i = 0; i < N; ++i)
{
ok &= !string_comparator(&sa_clone[i], &expect_sa[i]);
}
free(sa_clone);
assert( ok );
ok = 1;
ca_clone = malloc(N*sizeof(item_t));
assert( ca_clone != NULL );
memcpy(ca_clone, ca, N*sizeof(item_t));
sort(ca_clone, N, sizeof(item_t), item_comparator);
for (i = 0; i < N; ++i)
{
ok &= !item_comparator(&ca_clone[i], &expect_ca[i]);
}
free(ca_clone);
assert( ok );
}
void test_insertion_sort()
{
test_sort_algorithm(upo_insertion_sort);
}
int main()
{
printf("Test case 'insertion sort'... ");
fflush(stdout);
test_insertion_sort();
printf("OK\n");
return 0;
}
I wish to sort a second array as per the first array. e.g.
first = {1,8,7,2,4}
second = {9,7,2,10,3}
I want first to be unchanged and second to be sorted in the same relative order as the first. i.e. the lowest value is at index 0, the second lowest value is at index 3, third lowest value is at index 4 etc etc
second = {2,10,9,3,7}
I have already tried some code for the following
#include <stdio.h>
typedef struct
{
int num;
int pos;
}ArrType;
ArrType arrA[5] = {{1,0},{8,1},{7,2},{2,3},{4,4}};
ArrType arrB[5] = {{9,0},{7,1},{2,2},{10,3},{3,4}};;
int cmparr(const void *a, const void *b)
{
ArrType *tmpa, *tmpb;
tmpa = (ArrType*) a;
tmpb = (ArrType*) b;
return(arrA[tmpa->pos].num - arrA[tmpb->pos].num);
}
int main(void)
{
int i;
qsort(arrB,5, sizeof(ArrType), cmparr);
for (i=0; i<5; i++)
{
printf ("%d ",arrB[i].num);
}
return (0);
}
The actual output is
9 10 3 2 7
I am open to a different data structure, but arrB should only be sorted one time.
I have seen some solutions for this in C++, Javascipt and other languages. But there is not a solution in C.
Edit - These arrays would be quite large in the final program. I am looking for a single sorting operation. i.e. single call to qsort
You need to create the meta-data that matches the desired ordering (i.e an array of indexes). Then apply that meta-data to the second array.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int first[] = {1,8,7,2,4};
int second[] = {9,7,2,10,3};
int compare(const void * a, const void * b);
int binary_search(int array[], int min, int max, int target);
void print_array(int * array, int c);
int main()
{
int idx;
int c = sizeof(first)/sizeof(int);
int * sorted = NULL;
int * indexes = NULL;
int * result = NULL;
if (NULL == (sorted = malloc(sizeof(first)))) {
return -1;
}
memcpy(sorted, first, sizeof(first));
if (NULL == (indexes = malloc(sizeof(first)))) {
free(sorted);
return -1;
}
memset(indexes, -1, sizeof(first));
if (NULL == (result = malloc(sizeof(second)))) {
free(sorted);
free(indexes);
return -1;
}
memset(result, -1, sizeof(second));
// 1st: Sort the reference array
qsort (sorted, c, sizeof(int), compare);
// 2nd: Record the position of each sorted element in the original array (this is your meta-data)
for (idx=0; idx<c; idx++) {
indexes[idx] = binary_search(sorted, 0, c, first[idx]);
}
// 3rd sort the target array
memcpy(sorted, second, sizeof(second));
qsort (sorted, c, sizeof(int), compare);
// 4th apply the stored positions to the sorted target array
for (idx = 0; idx < c; idx++) {
result[idx] = sorted[indexes[idx]];
}
print_array(result, c);
free(result);
free(indexes);
free(sorted);
return 0;
}
int compare(const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
int binary_search(int array[], int min, int max, int target)
{
int mid;
while (min <= max)
{
mid = min + (max - min)/2;
if (target > array[mid])
min = mid + 1;
else if (target < array[mid])
max = mid - 1;
else
return mid;
}
return -1;
}
void print_array(int * array, int c)
{
for(int i = 0; i < c; i++) {
printf("%d ", array[i]);
}
printf("\n");
}
Demo
Here is my approach, it uses qsort twice and arrC contains the result.
#include <stdio.h>
typedef struct
{
int num;
int pos;
}ArrType;
ArrType arrA[5] = {{1,0},{8,1},{7,2},{2,3},{4,4}};
int arrB[5] = {9,7,2,10,3};;
int arrC[5];
int cmpInt(const void *a, const void *b)
{
return(*a - *b);
}
int cmp(const void *a, const void *b)
{
ArrType *tmpa, *tmpb;
tmpa = (ArrType*) a;
tmpb = (ArrType*) b;
return(tmpa->num - tmpb->num);
}
int main(void)
{
int i;
qsort(arrA,5, sizeof(ArrType), cmp);
qsort(arrB,5, sizeof(ArrType), cmpInt);
for (i=0; i<5; i++)
{
arrC[arrA[i].pos] = arrB[i];
}
return (0);
}
Since C doesn't have a lambda compare (which could be used to sort an array of indexes according to first[]), the code below sorts an array of pointers ap[] to the elements of first[] using qsort(). Using pointers eliminates the need to pass an array name as a parameter for the compare function, which in turn allows the compare function to work with qsort(). The expression (ap[i]-first) converts a pointer into an index. Next second[] is sorted, also using qsort(). Then ap[] is used as a set of ranks to reorder second[] in place and in O(n) time.
To explain reorder by rank versus reorder by index:
dst[rank[i]] = src[i]; /* reorder by rank */
dst[i] = src[index[i]]; /* reorder by index */
Example code:
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
/* compare for ptr to integer */
int cmppi(const void *p0, const void *p1){
return (*(int *)p0 - *(int *)p1);
}
/* compare for ptr to ptr to integer */
int cmpppi(const void *p0, const void *p1){
return (**(int **)p0 - **(int **)p1);
}
int main()
{
int first[] = {1, 8, 7, 2, 4};
int second[] = {9, 7, 2,10, 3};
int **ap; /* array of pointers */
int *tmpp;
int tmpi;
size_t i, j;
/* allocate and generate array of pointers to first[] */
ap = (int **)malloc(sizeof(first)/sizeof(first[0])*sizeof(int *));
for(i = 0; i < sizeof(first)/sizeof(first[0]); i++)
ap[i] = &first[i];
/* sort ap */
qsort(ap, sizeof(first)/sizeof(first[0]), sizeof(int *), cmpppi);
/* sort second */
qsort(second, sizeof(second)/sizeof(second[0]), sizeof(int), cmppi);
/* reorder ap and second in place using ap as rank (O(n) time) */
for (i = 0; i < sizeof(second) / sizeof(second[0]); i++){
while(i != (j = ap[i] - first)){
tmpp = ap[i]; /* swap(ap[i], ap[j]) */
ap[i] = ap[j];
ap[j] = tmpp;
tmpi = second[i]; /* swap(second[i], second[j] */
second[i] = second[j];
second[j] = tmpi;
}
}
/* display second[] */
for (i = 0; i < sizeof(second) / sizeof(second[0]); i++)
printf("%3d", second[i]);
printf("\n");
free(ap);
return 0;
}
#include <stdio.h>
void Heapify(int num[], int start, int end)
{
int root = start;
while(root*2+1<=end)
{ // at least one child exists
int swap = root;
int lchild = root*2+1;
int rchild = root*2+2;
if(num[swap]<num[lchild]){
swap = lchild;
}
if(rchild<=end && num[swap]<num[rchild]){
swap = rchild;
}
if(swap!=root){
// swap here
int temp = num[root];
num[root] = num[swap];
num[swap] = temp;
root = swap;
}
else
return;
}
}
void buildHeap(int num[]) {
int length=sizeof(num)/sizeof(num[0]);
int start = (length/2)-1; // Starting from last parent
int end = length-1;
while(start>=0){
Heapify(num,start, end);
if(start==0)
break;
start= start-1;
}
}
void heapsort(int num[]) {
int length=sizeof(num)/sizeof(num[0]);
printf("length = %d ", length); // length = 1 (Wrong)
buildHeap(num);
int i;
//for (i = 0; i < length; i++)
//printf("%d ",num[i]);
int end = length-1;
while(end>0){
// swap first elem with last
int temp = num[0];
num[0] = num[end];
num[end] = temp;
Heapify(num,0,end-1);
end--;
}
}
int main() {
int num[]={1,7,-32,4,101,-99,16,3};
heapsort(num);
return 0;
}
http://codepad.org/zcfNOtye
When I print it in main, the length is showing correct but inside the function(heap sort), its showing wrong. I can't find any mistakes in passing the array. What am I missing?
Arrays decay to pointers when passed as parameters, you need to pass the length of the array as a separate parameter.
I.e.: you can't find the length of the array like this.
void buildHeap(int num[]) {
int length=sizeof(num)/sizeof(num[0]);
}
sizeof(num) will return sizeof(int*).