I can sort a array of pointers to words so that they are ordered alphabetically, the problem is that I need to ALSO sort an integer array (the number of times that specific word is used) so that the integers are in the same place as their respective words:
my code:
for (i = 0; i < numWords; i++) {
// prints out the words and their frequency respectively
printf("%s - %d\n", dictionary[i], frequency[i]);
}
//sorts the dictionary so that the words are 'alphabetical'
qsort(dictionary, numWords, sizeof(char *), rstrcmp);
printf("\nafter qsort\n"); //checkmark
for (i = 0; i < numWords; i++) {
// prints the word list alphabetically, but the frequencies are no longer matched
printf("%s - %d\n", dictionary[i], frequency[i]);
}
...comparison function V
int rstrcmp(const void *p1, const void *p2) {
return strcmp(*(char * const *)p1, *(char * const *)p2);
}
A simple thing to do would be to use a struct to store word/frequency pairs and then sort an array of these structs.
For example:
struct WordFrequency
{
const char * word;
int frequency;
} wordFreqs[numWords]; // Assumes numWords is static/global and constant...
Then:
for (i = 0; i < numWords; i++) {
printf("%s - %d\n", dictionary[i], frequency[i]);
wordFreqs[i].word = dictionary[i];
wordFreqs[i].frequency = frequency[i];
}
//sorts the dictionary so that the words are 'alphabetical'
qsort(wordFreqs, numWords, sizeof(struct WordFrequency), wfcmp);
for (i = 0; i < numWords; i++) {
printf("%s - %d\n", wordFreqs[i].word, wordFreqs[i].frequency);
}
And:
int wfcmp(const void *p1, const void *p2) {
return strcmp(((const struct WordFrequency *)p1)->word, ((const struct WordFrequency *)p2)->word);
}
The standard qsort() function cannot do as you wish directly.
All else apart, how does it know (or how do you tell it) which two arrays to sort in parallel?
You either have to change the data structure (use an array of a structure type), or you have to write your own sort function. Of the two, changing the data structure is probably the easier.
There is another option — but a somewhat contorted one. You could create an array of int with entries such that:
for (int i = 0; i < N; i++)
index[i] = i;
You then pass this array to the sort function, along with a comparator that knows the base addresses of the two arrays. The qsort() function permutes the data in the array; the comparator looks at the data in the other arrays. The other two arrays have to be global (at least file scope) variables, or you need global variables that are pointers that can be initialized with the the base addresses of the two arrays.
After the sort, you can use array1[index[i]] and array2[index[i]] to access the ith element of the sorted arrays.
One other option if you're on BSD: you could use the qsort_r() function:
void qsort_r(void *base, size_t nel, size_t width, void *thunk,
int (*compar)(void *, const void *, const void *));
The 'thunk' is a pointer that's passed to the comparator as the first argument. You could use this with the index-array scheme to pass the pointers to the two arrays into the comparator, so you wouldn't need file scope variables at all. You still can't do two independent swaps, though, so you'd have to use the index-array scheme.
One approach that you might find useful for sorting parallel arrays: create an array of integers (size_ts to be strictly correct) and initialize it with the values 0 through numWords-1. Then qsort that array using a comparison function that does strcmp(dictionary[*(int *)p1], dictionary[*(int *)p2], then use the sorted array of indices to permute both dictionary and frequency at the same time (this is very easily done by copying, or a little less easily done in-place with swaps: here is an example of the latter).
Turix probably has the better solution though — using an array of structs instead of two arrays avoids the whole problem.
Related
I want to use a struct to contain some data and passing them between different functions in my program,this struct has to contain a dynamic 2D array (i need a matrix) the dimensions change depending on program arguments.
So this is my struct :
struct mystruct {
int **my2darray;
}
I have a function that read numbers from a file and has to assign each of them to a cell of the struct array.
I tried doing this :
FILE *fp = fopen(filename, "r");
int rows;
int columns;
struct mystruct *result = malloc(sizeof(struct mystruct));
result->my2darray = malloc(sizeof(int)*rows);
int tmp[rows][columns];
for(int i = 0;i<rows;i++) {
for(int j = 0;j<columns;j++) {
fscanf(fp, "%d", &tmp[i][j]);
}
result->my2darray[i]=malloc(sizeof(int)*columns);
memcpy(result->my2darray[i],tmp[i],sizeof(tmp[i]));
}
But this is giving me a strange result : all the rows are correctly stored except for the first.
(I'm sure that the problem is not in the scanning of file).
While if i change the fourth line of code in this :
result->my2darray = malloc(sizeof(int)*(rows+1));
it works fine.
Now my question is why this happens?
Here's an answer using some "new" features of the language: flexible array members and pointers to VLA.
First of all, please check Correctly allocating multi-dimensional arrays. You'll want a 2D array, not some look-up table.
To allocate such a true 2D array, you can utilize flexible array members:
typedef struct
{
size_t x;
size_t y;
int flex[];
} array2d_t;
It will be allocated as a true array, although "mangled" into a single dimension:
size_t x = 2;
size_t y = 3;
array2d_t* arr2d = malloc( sizeof *arr2d + sizeof(int[x][y]) );
Because the problem with flexible array members is that they can neither be VLA nor 2-dimensional. And although casting it to another integer array type is safe (in regards of aliasing and alignment), the syntax is quite evil:
int(*ptr)[y] = (int(*)[y]) arr2d->flex; // bleh!
It would be possible hide all this evil syntax behind a macro:
#define get_array(arr2d) \
_Generic( (arr2d), \
array2d_t*: (int(*)[(arr2d)->y])(arr2d)->flex )
Read as: if arr2d is a of type array2d_t* then access that pointer to get the flex member, then cast it to an array pointer of appropriate type.
Full example:
#include <stdlib.h>
#include <stdio.h>
typedef struct
{
size_t x;
size_t y;
int flex[];
} array2d_t;
#define get_array(arr2d) \
_Generic( (arr2d), \
array2d_t*: (int(*)[(arr2d)->y])(arr2d)->flex )
int main (void)
{
size_t x = 2;
size_t y = 3;
array2d_t* arr = malloc( sizeof *arr + sizeof(int[x][y]) );
arr->x = x;
arr->y = y;
for(size_t i=0; i<arr->x; i++)
{
for(size_t j=0; j<arr->y; j++)
{
get_array(arr)[i][j] = i+j;
printf("%d ", get_array(arr)[i][j]);
}
printf("\n");
}
free(arr);
return 0;
}
Advantages over pointer-to-pointer:
An actual 2D array that can be allocated/freed with a single function call, and can be passed to functions like memcpy.
For example if you have two array2d_t* pointing at allocated memory, you can copy all the contents with a single memcpy call, without needing to access individual members.
No extra clutter in the struct, just the array.
No cache misses upon array access due to the memory being segmented all over the heap.
The code above never sets rows and columns, so the code has undefined behavior from reading those values.
Assuming you set those values properly, this isn't allocating the proper amount of memory:
result->my2darray = malloc(sizeof(int)*rows);
You're actually allocating space for an array of int instead of an array of int *. If the latter is larger (and it most likely is) then you haven't allocated enough space for the array and you again invoke undefined behavior by writing past the end of allocated memory.
You can allocate the proper amount of space like this:
result->my2darray = malloc(sizeof(int *)*rows);
Or even better, as this doesn't depend on the actual type:
result->my2darray = malloc(sizeof(*result->my2darray)*rows);
Also, there's no need to create a temporary array to read values into. Just read them directly into my2darray:
for(int i = 0;i<rows;i++) {
result->my2darray[i]=malloc(sizeof(int)*columns);
for(int j = 0;j<columns;j++) {
fscanf(fp, "%d", &result->my2darray[i][j]);
}
}
In your provided code example, the variables rows and columns have not been initialized before use, so they can contain anything, but are likely to be equal to 0. Either way, as written, the results will always be unpredictable.
When a 2D array is needed in C, it is useful to encapsulate the memory allocation, and freeing of memory into functions to simplify the task, and improve readability. For example, in your code the following line will create an array of 5 pointers, each pointing to 20 int storage locations: (creating 100 index addressable int locations.)
int main(void)
{
struct mystruct result = {0};
result.my2darray = Create2D(5, 20);
if(result.my2darray)
{
// use result.my2darray
result.my2darray[0][3] = 20;// for simple example, but more likely in a read loop
// then free result.my2darray
free2D(result.my2darray, 5);
}
return 0;
}
Using the following two functions:
int ** Create2D(int c, int r)
{
int **arr;
int y;
arr = calloc(c, sizeof(int *)); //create c pointers (columns)
for(y=0;y<c;y++)
{
arr[y] = calloc(r, sizeof(int)); //create r int locations for each pointer (rows)
}
return arr;
}
void free2D(int **arr, int c)
{
int i;
if(!arr) return;
for(i=0;i<c;i++)
{
if(arr[i])
{
free(arr[i]);
arr[i] = NULL;
}
}
free(arr);
arr = NULL;
}
Keep in mind that what you have created using this technique is actually 5 different pointer locations each pointing to a set of 20 int locations. This is what facilitates the use of array like indexing, i.e. we can say result.my2darray[1][3] represents the second column, forth row element of a 5X20 array, when it is not really an array at all.
int some_array[5][20] = {0};//init all elements to zero
Is what is commonly referred to in C an int array, also allowing access to each element via indexing. In actuality (Even though commonly referred to as an array.) it is not an array. The location of elements in this variable are stored in one contiguous location in memory.
|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0... (~ 82 more)
But C maintains the locations such that they are all indexable as an 2D array.
as i stated before, i am learning C from home, and hitting some bumps on the way. Thanks to you all i am learning bit by bit.
I wrote something that made sense in my head and taking in account what i've learned so far:
int exercicio4a(int *s){
int tmp, i;
int nmax = strlen(s);
int z[nmax];
for(i=0; i!=nmax; i++){
if(s[i]>=s[i+1]){
z[i]=s[i+1];
}else{
z[i]=s[i];
}
}
return z;
}
main(){
int x, y, nmax;
int str[10];
printf("Organize a bunch of numbers:\n");
nmax = 9;
while(nmax!=0){
printf("Enter the random int number %d :\n", nmax);
scanf("%d", &str[nmax]);
nmax--;
}
printf("%s \n", exercicio4a(str) );
}
Needless to say that this is garbage as it doesn't take me anywhere!
One last thing, i would like to know if there is a way to use GDB in order to detect a malfunction in this code for example.
Cheers!
Well, you need to clarify your terms. You want to sort an array of integers, which you scan from stdin, I assume. Don't call this array a string, it is bad terminology. You also need to decide if exercicio4a should return a string of ascii characters, where the integers are inserted into a string, or an array of integers.
You really should be taking an integer array for your function and either sorting in place, or allocating a new one and returning it.
Now let's look at the problems with your code:
nmax = 9;
while(nmax!=0){
printf("Enter the random int number %d :\n", nmax);
scanf("%d", &str[nmax]);
nmax--;
}
You are exiting the loop when nmax == 0, but you never scan an integer into that location. To fix this:
nmax=10;
while (nmax--) {
//printf
scanf("%d", str + nmax); //or &str[nmax]; these are equal
}
Next: int exercicio4a(int *s){... This signature is incorrect. Assuming you don't want to sort in place, you want to return a new array so you should have int *exercicio4a(int *s){... You want to return a pointer to the first integer in the array.
Next int z[nmax]; This array is a local variable. It will go out of scope when you return from the function so the behavior of using it after you return is undefined! Instead you want to dynamically allocate space for the sorted array using int *z = calloc(nmax, sizeof(int)); You will need to free the returned array after the calling function is done using it to avoid memory leaks.
Next: printf("%s \n", exercicio4a(str) ); Here you are trying to print an integer as a string (with the code you have). Even if you fix it to return an int* you will still be trying to print an array of integers as a string. What you should do is use a loop to print the array:
nmax = 10;
int *ptr = exercicio4a(str); //only after you fix exercicio
while (nmax--)
printf("%d ", *ptr++);
Lastly, your loop does not perform a sort. It is an attempt to swap adjacent elements that are out of order. It does not perform this functionality correctly, but don't bother getting that working since it won't even implement a sorting algorithm. I suggest you read about insertion, bubble, and selection sort to get a feel for how to implement those algorithms if you want to learn how to do sorts on your own. Most of the time though, you will want to use a library function to sort an array. If you want to keep an un-sorted copy of your data, make a qsort wrapper:
int compare (void *one, void *two) {
return *(int *)one - *(int *)two;
}
int *my_sort(int *arr, int size) {
int *sorted = calloc(size, sizeof(int));
memcpy(sorted, arr, size * sizeof(int));
qsort(sorted, size, sizeof(int), compare);
return sorted;
}
I am loading some data into struct.
struct test {
char x[101];
char y[101];
int z;
};
Then I create memory for structs
struct test * data;
data = malloc(10 * sizeof(struct test));
And fill data like this
data[0].z = 123;
This works alright. But I wanna sort these structs. Like sort them depending on z attribute.
My idea was to create a new array and fill it with pointers which will point to the right struct.
Can somebody tell me how or if there is better way?
Thanks
This depends on your goal. If you are trying to figure out what would be most programmer efficient, then creating an ordering functor based on the z attribute of your struct, and sorting the list directly, is easiest.
However, if you are concerned with program efficiency, then it will be faster to sort pointers, as suggested by Fiddling Bits. However, you must keep in mind that this will give you a sorted list of pointers- your data array will still be in the same order.
For instance, if datapoints is your array of pointers, and you wanted to sort by the z value, you could define the comparison
int compare(const void *a, const void *b)
{
return ( (*(test *)a).z -(*(test *)b).z );
}
And then call
qsort( datapoints, 10, sizeof(test), compare);
Full documentation for qsort can be found here:
One way to do this is using qsort, the general sorting algorithm provided in the standard library for sorting sequences of user-defined data. With a goal of doing the following:
the source data must remain un-touched.
the "sorted" access must be provided via a list of pointers to the untouched data from above
this is one way to do that using the qsort() standard library function:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
struct test {
char x[101];
char y[101];
int z;
};
int cmp_test_ptrs(const void* arg1, const void* arg2)
{
struct test const * lhs = *(struct test const * const*)arg1;
struct test const * rhs = *(struct test const * const*)arg2;
return (lhs->z < rhs->z) ? -1 : (rhs->z < lhs->z);
}
int main()
{
srand((unsigned int)time(0));
// populate data array.
struct test * data = malloc(10 * sizeof(*data));
for (int i=0; i<10; ++i)
{
data[i].z = rand() % 20;
printf("%d ", data[i].z);
}
printf("\n");
// allocate a pointer array to use as a sort-bed, copying each
// structure address into this pointer array afterward
struct test **ptrs = malloc(10 * sizeof(*ptrs));
for (int i=0; i<10; ++i)
ptrs[i] = data+i;
// sort the pointer bed using our comparator
qsort(ptrs, 10, sizeof(*ptrs), cmp_test_ptrs);
// ptrs now has sorted pointers. Note the dereference for access
// to the actual data, which remains where it originally was.
for (int i=0; i<10; ++i)
printf("%d ", ptrs[i]->z);
printf("\n");
free(ptrs);
free(data);
return 0;
}
Sample Output
11 7 6 17 8 8 11 4 7 5
4 5 6 7 7 8 8 11 11 17
Important to note is the original structure array remained untouched. We sorted a sequence of pointers, not the actual structures themselves, and used what those pointers pointed-to as the criteria for the sort.
Anyway, I hope it helps. Study the comparator and the setup for qsort() carefully. They're important. You can read more about qsort() here.
Or you can just sort them in the same array and probably save some memory (4 bytes for a pointer of any type) :P
Doesn't really matter though, pointers'll work fine I guess.
But I think that in some cases pointers will be more useful as if you would sort it in the array you'll need a temporary struct defined to contain structs when you're sorting and if you're struct is big than you'll actually take a lot more memory than 4 bytes.
+Also remember that when defining a pointer to a struct - access it with -> operator.
Usage: STRUCT_POINTER_NAME->VARIABLE
I need to write a function that sums monoms with the same power,
the monoms are defined by the following struct:
typedef struct monom {
int coefficient;
int power;
}MONOM;
And the function I wrote from the job is:
int sumMonomsWithSamePower(MONOM** polynomial, int size)
{
int i, powerIndex = 0;
for (i = 0; i < size; i++)
{
if ((polynomial[powerIndex])->power == (polynomial[i])->power)
{
if (powerIndex != i)
(polynomial[powerIndex])->coefficient += (polynomial[i])->coefficient;
}
else
powerIndex++;
}
powerIndex++;
*polynomial = (MONOM*)realloc(polynomial, powerIndex);
return powerIndex;
}
Which is being called with the following call:
*polySize = sumMonomsWithSamePower(&polynomial, logSize);
polynomial array is being sent to the function as a sorted array of MONOMs (sorted ascending by powers).
My problem is that on the 7th line of sumMonomsWithSamePower() the function crashes since it can't see the elements in the array by the following way. When I put the elements of the array in Watch list in my debugger I also can't see them using polynomial[i], but if I use (polynomial[0]+i) I can see them clearly.
What is going on here?
I assume outside sumMonomsWithSamePower() you have allocated polynomial with something like polynomial = malloc( size * sizeof(MONOM) ); (everything else wouldn't be consistant to your realloc()). So you have an array of MONOMs and the memory location of polynomial[1] is polynomial[0] + sizeof(MONOM) bytes.
But now look at polynomial in sumMonomsWithSamePower() In the following paragraph I will rename it with ppoly (pointer to polynomial) to avoid confusing it with the original array: here it is a MONOM **, so ppoly[1] addresses the sizeof(MONOM *) bytes at the memory location ppoly[0] + sizeof(MONOM *) and interpretes them as pointer to a MONOM structure. But you have an array of structs, not an array of pointers. Replace your expressions by (*ppoly)[i].power (and all the others accordingly of course) and that part will work. By the way that's excactly the difference of the two debugger statements you have mentioned.
Besides, look at my comments concerning the use of powerIndex
Is it possible to create an array of arrays in c
Thank you.
It's the same as for example in PHP:
int arrayInArray[10][50];
You read data out of it with:
printf("%d", arrayInArray[3][37]);
I bet you mean Multi Dimensional Array instead of "array of arrays".
Some links for this topic:
http://www.dfstermole.net/OAC/harray2.html
http://webster.cs.ucr.edu/AoA/Windows/HTML/Arraysa2.html
For using an array of arrays with all the power of C you should have some knowledge of dynamic memory handling in c, with the functions malloc, realloc, and free, and some knowledge about pointers. For this example that you ask a possible solution would be this:
#include <stdio.h>
void main(int argc, char* argv[]){
int** myArray; /* This would be a double pointer, because you want a two dimension array.*/
int firstDimension = 10;
int secondDimension = 20;
int i;
myArray = (int**)malloc(firstDimension*sizeof(int*)); This way you initialize the first dimension of the array.
for(i = 0; i < firstDimension; i++){
myArray[i] = (int*)malloc(secondDimension*sizeof(int));
}
/*Once you have the array initialized, you can access in the way myArray[i][j];*/
/*For releasing resources */
for(i = 0; i < firstDimension; i++){
free(myArray[i]);
}
free(myArray);
}
This is the dynamic way, the one that is teached on CS courses.
If you need an array of arrays then you should use structs.
typedef ArrayStruct* ArrayStructPtr;
struct ArrayStruct
{
void* array;//Node array
ArrayStructPtr arrays;//Pointer to sub arrays
};
int main()
{
ArrayStruct* a;//Declare Some Arrays
a=(ArrayStruct*)malloc(sizeof(ArrayStruct)*N);
for(int i=0;i<N;i++)
{
a[i].array=(void*)malloc(sizeof(int)*N);//Malloc the actual array
a[i].arrays=NULL;//Malloc subarrays if needed
}
//add subarray on array 0
ArrayStruck * temp=(ArrayStruct*)malloc(sizeof(ArrayStruct));
temp->array=(void*)malloc(sizeof(char)*MAXNAME*N);
temp->arrays=NULL;
a[0]=arrays=temp;
return 0;
}
What you need is a List Of arrays Where each node of the struct can hold an array and a pointer to another node.
The array type is void* to support int,float,char*.
So each array can have as many subarrays as you want.You can create 3 dimension Arrays if you want!