Sorting array of strings with qsort - c

This program takes an integer value which then determines the amount of strings that can be inputted, once the user has entered the amount of strings that they specified they may input another integer and then input those amount of strings. Once done the program sorts the strings based on their lengths in descending order. However the qsort doesn't work, it ends up outputting how the order of when the strings were originally entered.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int sort(const void * a, const void * b){
size_t fa = strlen((const char *)a);
size_t fb = strlen((const char *)b);
return (fa < fb) - (fa > fb);
}
int main(void){
char pointer[100];
int n;
scanf("%d", &n);
char** strings = malloc(n * sizeof(char*));
int i;
for (i = 0; i < n; i++){
scanf("%s", pointer);
strings[i] = malloc(sizeof(char) * (strlen(pointer) + 1));
strcpy(strings[i], pointer);
}
int m;
scanf("%d", &m);
strings = realloc(strings, (n + m) * sizeof(char*));
for (i = n; i < m + n; i++){
scanf("%s", pointer);
strings[i] = malloc(sizeof(char) * (strlen(pointer) + 1));
strcpy(strings[i], pointer);
}
int a;
int g;
int k = m + n;
qsort(strings , a, 100, sort);
for (g = 0; g < k; g++){
printf("%s", strings[g]);
printf("\n");
}
}

You're not calling qsort correctly at all.
The 2nd parameter is the number of elements in the "array" that you are sorting. You're currently passing it a which as others have pointed out isn't set to anything. Compiling your code with the "-Wall" option will show you those kinds of errors.
The 3rd parameter is the size of one of the elements in the "array", but you've confused this with the size of an unrelated variable pointer? You could write it like sizeof(strings[0]).
The finished call should look like qsort(strings,k,sizeof(strings[0]),sort);.
But that still won't work because your sort() function is being passed two pointers to elements in your "array" (char **) and you're treating them as two elements of the "array" (char *). So you'd want something like
size_t fa = strlen(*(char **)a);

Well, this:
int a;
int g;
int k = m + n;
qsort(strings , a, 100, sort);
makes no sense at all, a has no value so this is undefined behavior.
Also sort() is broken, it should just be strcmp().

Related

different ways to declare a matrix c

I don't really understand why method 1 works but not method 2. I don't really see why it works for characters and not an int.
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
/// WORK (METHODE 1)
char **string_array = malloc(sizeof(char **) * 10);
string_array[0] = "Hi there";
printf("%s\n", string_array[0]); /// -> Hi there
/// DOES NOT WORK (METHODE 2)
int **int_matrix = malloc(sizeof(int **) * 10);
int_matrix[0][0] = 1; // -> Segmentation fault
/// WORK (METHODE 3)
int **int_matrix2 = malloc(sizeof(int *));
for (int i = 0; i < 10; i++)
{
int_matrix2[i] = malloc(sizeof(int));
}
int_matrix2[0][0] = 42;
printf("%d\n", int_matrix2[0][0]); // -> 42
}
In terms of the types, you want to allocate memory for the type "one level up" from the pointer you're assigning it to. For example, an int pointer (an int*), points to one or more ints. That means, when you allocate space for it, you should allocate based on the int type:
#define NUM_INTS 10
...
int* intPtr = malloc(NUM_INTS * sizeof(int));
// ^^ // we want ints, so allocate for sizeof(int)
In one of your cases, you have a double int pointer (an int**). This must point to one or more int pointers (int*), so that's the type you need to allocate space for:
#define NUM_INT_PTRS 5
...
int** myDblIntPtr = malloc(NUM_INT_PTRS * sizeof(int*));
// ^^ "one level up" from int** is int*
However, there's an even better way to do this. You can specify the size of your object it points to rather than a type:
int* intPtr = malloc(NUM_INTS * sizeof(*intPtr));
Here, intPtr is an int* type, and the object it points to is an int, and that's exactly what *intPtr gives us. This has the added benefit of less maintenance. Pretend some time down the line, int* intPtr changes to int** intPtr. For the first way of doing things, you'd have to change code in two places:
int** intPtr = malloc(NUM_INTS * sizeof(int*));
// ^^ here ^^ and here
However, with the 2nd way, you only need to change the declaration:
int** intPtr = malloc(NUM_INTS * sizeof(*intPtr));
// ^^ still changed here ^^ nothing to change here
With the change of declaration from int* to int**, *intPtr also changed "automatically", from int to int*. This means that the paradigm:
T* myPtr = malloc(NUM_ITEMS * sizeof(*myPtr));
is preferred, since *myPtr will always refer to the correct object we need to size for the correct amount of memory, no matter what type T is.
Others have already answered most of the question, but I thought I would add some illustrations...
When you want an array-like object, i.e., a sequence of consecutive elements of a given type T, you use a pointer to T, T *, but you want to point to objects of type T, and that is what you must allocate memory for.
If you want to allocate 10 T objects, you should use malloc(10 * sizeof(T)). If you have a pointer to assign the array to, you can get the size from that
T * ptr = malloc(10 * sizeof *ptr);
Here *ptr has type T and so sizeof *ptr is the same as sizeof(T), but this syntax is safer for reasons explained in other answers.
When you use
T * ptr = malloc(10 * sizeof(T *));
you do not get memory for 10 T objects, but for 10 T * objects. If sizeof(T*) >= sizeof(T) you are fine, except that you are wasting some memory, but if sizeof(T*) < sizeof(T) you have less memory than you need.
Whether you run into this problem or not depends on your objects and the system you are on. On my system, all pointers have the same size, 8 bytes, so it doesn't really matter if I allocate
char **string_array = malloc(sizeof(char **) * 10);
or
char **string_array = malloc(sizeof(char *) * 10);
or if I allocate
int **int_matrix = malloc(sizeof(int **) * 10);
or
int **int_matrix = malloc(sizeof(int *) * 10);
but it could be on other architectures.
For your third solution, you have a different problem. When you allocate
int **int_matrix2 = malloc(sizeof(int *));
you allocate space for a single int pointer, but you immediately treat that memory as if you had 10
for (int i = 0; i < 10; i++)
{
int_matrix2[i] = malloc(sizeof(int));
}
You can safely assign to the first element, int_matrix2[0] (but there is a problem with how you do it that I get to); the following 9 addresses you write to are not yours to modify.
The next issue is that once you have allocated the first dimension of your matrix, you have an array of pointers. Those pointers are not initialised, and presumably pointing at random places in memory.
That isn't a problem yet; it doesn't do any harm that these pointers are pointing into the void. You can just point them to somewhere else. This is what you do with your char ** array. You point the first pointer in the array to a string, and it is happy to point there instead.
Once you have pointed the arrays somewhere safe, you can access the memory there. But you cannot safely dereference the pointers when they are not initialised. That is what you try to do with your integer array. At int_matrix[0] you have an uninitialised pointer. The type-system doesn't warn you about that, it can't, so you can easily compile code that modifies int_matrix[0][0], but if int_matrix[0] is pointing into the void, int_matrix[0][0] is not an address you can safely read or write. What happens if you try is undefined, but undefined is generally was way of saying that something bad will happen.
You can get what you want in several ways. The closest to what it looks like you are trying is to implement matrices as arrays of pointers to arrays of values.
There, you just have to remember to allocate the arrays for each row in your matrix as well.
#include <stdio.h>
#include <stdlib.h>
int **new_matrix(int n, int m)
{
int **matrix = malloc(n * sizeof *matrix);
for (int i = 0; i < n; i++)
{
matrix[i] = malloc(m * sizeof *matrix[i]);
}
return matrix;
}
void init_matrix(int n, int m, int **matrix)
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
matrix[i][j] = 10 * i + j + 1;
}
}
}
void print_matrix(int n, int m, int **matrix)
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
printf("%d ", matrix[i][j]);
}
printf("\n");
}
}
int main(void)
{
int n = 3, m = 5;
int **matrix = new_matrix(n, m);
init_matrix(n, m, matrix);
print_matrix(n, m, matrix);
return 0;
}
Here, each row can lie somewhere random in memory, but you can also put the row in contiguous memory, so you allocate all the memory in a single malloc and compute indices to get at the two-dimensional matrix structure.
Row i will start at offset i*m into this flat array, and index matrix[i,j] is at index matrix[i * m + j].
#include <stdio.h>
#include <stdlib.h>
int *new_matrix(int n, int m)
{
int *matrix = malloc(n * m * sizeof *matrix);
return matrix;
}
void init_matrix(int n, int m, int *matrix)
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
matrix[m * i + j] = 10 * i + j + 1;
}
}
}
void print_matrix(int n, int m, int *matrix)
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
printf("%d ", matrix[m * i + j]);
}
printf("\n");
}
}
int main(void)
{
int n = 3, m = 5;
int *matrix = new_matrix(n, m);
init_matrix(n, m, matrix);
print_matrix(n, m, matrix);
return 0;
}
With the exact same memory layout, you can also use multidimensional arrays. If you declare a matrix as int matrix[n][m] you will get what amounts to an array of length n where the objects in the arrays are integer arrays of length m, exactly as on the figure above.
If you just write that expression, you are putting the matrix on the stack (it has auto scope), but you can allocate such matrices as well if you use a pointer to int [m] arrays.
#include <stdio.h>
#include <stdlib.h>
void *new_matrix(int n, int m)
{
int(*matrix)[n][m] = malloc(sizeof *matrix);
return matrix;
}
void init_matrix(int n, int m, int matrix[static n][m])
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
matrix[i][j] = 10 * i + j + 1;
}
}
}
void print_matrix(int n, int m, int matrix[static n][m])
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
printf("%d ", matrix[i][j]);
}
printf("\n");
}
}
int main(void)
{
int n = 3, m = 5;
int(*matrix)[m] = new_matrix(n, m);
init_matrix(n, m, matrix);
print_matrix(n, m, matrix);
int(*matrix2)[m] = new_matrix(2 * n, 3 * m);
init_matrix(2 * n, 3 * m, matrix2);
print_matrix(2 * n, 3 * m, matrix2);
return 0;
}
The new_matrix() function returns a void * because the return type cannot depend on the runtime arguments n and m, so I cannot return the right type.
Don't let the function types fool you, here. The functions that take a matrix[n][m] argument do not check if the matrix has the right dimensions. You can get a little type checking with pointers to arrays, but pointer decay will generally limit the checking. The last solution is really only different syntax for the previous one, and the arguments n and m determines how the (flat) memory that matrix points to is interpreted.
The method 1 works only becuse you assign the char * element of the array string_array with the reference of the string literal `"Hi there". String literal is simply a char array.
Try: string_array[0][0] = 'a'; and it will fail as well as you will dereference not initialized pointer.
Same happens in method 2.
Method 3. You allocate the memory for one int value and store the reference to it in the [0] element of the array. As the pointer references the valid object you can derefence it (int_matrix2[0][0] = 42;)

C - writing and reading a dynamical array

I'm trying to create a 2D array for storing names (with max 50 characters each). I have written a code, but it isn't working properly, where's the problem? (I can do this with statics arrays, however at the beginning my program won't know how many names I will want to store in the array). Here's my code:
#include<stdio.h>
#include<stdlib.h>
int main()
{
int n=5;
int size=51;
char *a_name=(char*)malloc(n*size*sizeof(char));
for(int i=0;i<n;i++){
scanf("%s",&a_name[i]);
}
for(int i=0;i<=n;i++){
printf("%s\n",a_name[i]);
}
return 0;
}
What you need is not an array of char but an array of char *.
Try this:
int n = 5, size = 51;
char **name_array = (char **)malloc(sizeof(char *) * n);
for (int i = 0; i < n; ++i) {
name_array[i] = (char *)malloc(sizeof(char) * size);
// You may initialize the array first.
scanf("%s\n", name_array[i]);
}
Remember to release the memory when you no longer need the names.

How to sort an `int **` array in C with native qsort

I've been unable to find any question regarding this, and I think I'm going a bit crazy trying to figure this out.
I have the following code:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
int cmp_int(const void *a, const void *b)
{
return * (int *)a - * (int *)b;
}
int main(int argc, char *argv[])
{
int n = 10;
int **arr = calloc(n, sizeof(int *));
srand((unsigned int) time(NULL));
for (int i = n-1; i >= 0; i--) {
arr[i] = calloc(1, sizeof(int));
*(arr[i]) = rand() % 1000;
}
for (int i = 0; i < n; i++)
printf("%d ", *(arr[i]));
printf("\n");
qsort(arr, 10, sizeof(void *), cmp_int);
for (int i = 0; i < n; i++)
printf("%d ", *(arr[i]));
printf("\n");
free(arr);
return 0;
}
It's super basic, right? According to the manpage, the first argument is the pointer to the base element and the third argument is the size. However, I fail to get the array as a sorted result. I'm still really confused as to what the first and third argument to qsort should be since I suspect that that's where the fault is.
Any help is appreciated.
Thanks.
Edit: I should add that this code obviously does no error checking and that I was trying to test qsort with a double-pointer array of integers, so while yes I could use a regular array that was not the intended purpose of this code (it’s actually part of a bigger segment in a separate program).
Your program makes my head hurt. The reason you're not getting a correct sort is that the comparison function is wrong. It would need to be return **(int **)a - **(int **)b; to get a correct result.
However it's not worth fixing the problem that way. A list of at least some of the issues:
If you don't use argc and argv, don't declare them.
Cast in the srand call is unnecessary.
int comparison by subtraction is a bad idea because it can overflow.
calloc returns should always be checked for null (out of memory) results.
calloc isn't needed at all. Use a variable length array.
There's no need to allocate an array of pointers to ints. Just allocate an array of ints. Then your comparison works as-is.
The qsort call uses a hard constant 10 rather than n.
It's less error prone to give the element size by dereferencing the array name.
At the end you free the "spine" array but never the integer elements.
You should factor out a function to print the array.
Here's a version that addresses these.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int cmp_int(const void *va, const void *vb)
{
int a = *(int *)va, b = *(int *) vb;
return a < b ? -1 : a > b ? +1 : 0;
}
void print(int *a, int n) {
for (int i = 0; i < n; ++i) printf("%d ", a[i]);
printf("\n");
}
int main(void)
{
int n = 10, a[n];
srand(time(0));
for (int i = 0; i < n; ++i) a[i] = rand() % 1000;
print(a, n);
qsort(a, n, sizeof a[0], cmp_int);
print(a, n);
return 0;
}
The problem you are having is failing to account for one additional level of indirection created by allocating for a block of pointers with int **arr = calloc (n, sizeof *arr); and then allocating storage for a single int to each pointer with arr[i] = calloc (1, sizeof *arr[i]).
Since the int compare (const void *a, const void *b) compare function for qsort expects a pointer to the elements of the array being sorted, both a and b above will be pointer-to-pointer to int in your case requiring 2 levels of indirection be dereferenced before the integer values can be compared.
Rather than cmp_int, you actually need a cmp_int_ptr compare function. It can be written as:
int cmp_int_ptr (const void *a, const void *b)
{
int *ai = *(int * const *)a,
*bi = *(int * const *)b;
return (*ai > *bi) - (*ai < *bi);
}
(note: the two levels of indirection in the cast (int * const *)... which can also be written as (int **), but to correspond to the parameter type (const void *) the (int * const *) is proper)
Putting that in place, adding validations for each allocation and cleaning up your calloc type-size specification by using the dereferenced pointer itself to set type-size, you can do:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
int cmp_int_ptr (const void *a, const void *b)
{
int *ai = *(int * const *)a,
*bi = *(int * const *)b;
return (*ai > *bi) - (*ai < *bi);
}
int main (void) {
int n = 10;
int **arr = calloc (n, sizeof *arr);
if (!arr) {
perror ("calloc-arr");
return 1;
}
srand((unsigned int) time(NULL));
for (int i = 0; i < n; i++) {
if (!(arr[i] = calloc (1, sizeof *arr[i]))) {
perror ("calloc-arr[i]");
return 1;
}
*(arr[i]) = rand() % 1000;
}
for (int i = 0; i < n; i++)
printf (" %d", *(arr[i]));
putchar ('\n');
qsort (arr, 10, sizeof *arr, cmp_int_ptr);
for (int i = 0; i < n; i++) {
printf (" %d", *(arr[i]));
free (arr[i]); /* don't forget to free your int allocated */
}
putchar ('\n');
free(arr); /* now free pointers */
}
Example Use/Output
$ ./bin/qsortptrtoint
654 99 402 264 680 534 155 533 397 678
99 155 264 397 402 533 534 654 678 680
Look things over and let me know if you have questions.

C Malloc Multidimensional Char Array

I would like to dynamically allocate (malloc) a multidimensional character array in C. The array would have the following format:
char *array[3][2] = {
{"one","two"},
{"three","four"},
{"five","six"}
};
Before the array would be created, I would already know the number of rows and the lengths of all of the characters arrays in the multidimensional array.
How would I malloc such a character array?
Thanks in advance!
This is one way to allocate a two dimensional array of char *.
Afterwards, you can assign the contents like a[1][2] = "foo";
Note that the elements of the array are initialized to (char *)0.
#include <stdio.h>
#include <stdlib.h>
char ***alloc_array(int x, int y) {
char ***a = calloc(x, sizeof(char **));
for(int i = 0; i != x; i++) {
a[i] = calloc(y, sizeof(char *));
}
return a;
}
int main() {
char ***a = alloc_array(3, 2);
a[2][1] = "foo";
printf("%s\n", a[2][1]);
}
[Charlies-MacBook-Pro:~] crb% cc xx.c
[Charlies-MacBook-Pro:~] crb% a.out
foo
First of all, arrays are typically stored in Row Major form, so in reality you have a vector six elements long, each entry is a char * ptr. That is, the elements labelled by row, column are similar to:
char *r1c1, *r1c2, *r2c1, *r2c2, *r3c1, *r3c1;
Thus, do a SIMPLE malloc of:
char *matrix = malloc(3*2*sizeof(char *));
Then set the elements as:
matrix[0] = "one";
matrix[1] = "two";
matrix[2] = "three";
matrix[3] = "four";
matrix[4] = "five";
matrix[5] = "six";
Finally, to test this write a nested loop as:
for (int r=0; r<3; r++)
{
for (int c=0; c<2; c++);
{
printf("%s\n",matrix[r][c]);
}
}
Note, how a matrix is treated first as a vector then as a matrix. C doesn't care!!
char *array[3][2] is nothing but a two dimensional array of pointers. Hence you need the storage space of 3*2*sizeof(char *) to store the pointers.
As you mentioned, the pointers are actually pointing to zero-terminated strings and you may like the strings to be malloc'ed as well. Assuming the total length of all the strings to be N (including zero-termination), the storage space needed is (3*2*sizeof(char *) + N).
Allocate memory for the above mentioned size and the copy the strings yourselves as below.
In the following code, we assume that the number of columns (2) is a constant
char *(*dst)[2] = (char *(*)[2]) malloc(3*2*sizeof(char *) + N);
char * s = ((char *) dst) + (3*2*sizeof(char *));
for (i = 0; i < 3; i++)
{
for (j = 0; j < 2; j++)
{
strcpy(s, src[i][j]);
dst[i][j] = s;
s += strlen(s)+1;
}
}
NOTE: In the above code, 'dst' is a pointer that points to the first row of the 2D array of char *.
If the number of columns is not constant, the syntax changes a bit, but the storage size is the same.
char **dst = (char **) malloc(3*2*sizeof(char *) + N);
char * s = ((char *) dst) + (3*2*sizeof(char *));
for (i = 0; i < 3; i++)
{
for (j = 0; j < 2; j++)
{
strcpy(s, src[i][j]);
dst[i*2 + j] = s; /* 2 is the number of columns */
s += strlen(s)+1;
}
}
NOTE: Here 'dst' is a pointer that points to the first element of 1D array of char * and the 2D indexing is done manually.
The above examples assume that the string lengths will not change after allocation. If the strings can change at any point in time after allocation, then it is better to allocate for each string separately.
Keep it simple, Sheldon. The answer you've selected uses a char ***, which is not even close to the equivalent of a char *[2][3]. The difference is in the number of allocations... An array only ever requires one.
For example, here's how I'd retro-fit the answer you selected. Notice how much simpler it is?
#include <stdio.h>
#include <stdlib.h>
void *alloc_array(size_t x, size_t y) {
char *(*a)[y] = calloc(x, sizeof *a);
return a;
}
int main() {
char *(*a)[2] = alloc_array(3, 2);
a[2][1] = "foo";
printf("%s\n", a[2][1]);
}
In case you arrive in this page, wanting to create an array like int myarray[n][M] (which is slighly different from the question since they want an array of string), where M is fixed and n can vary (for example if you want an array of coordinates...), then you can just do:
int (*p)[M] = malloc(n*sizeof *p);
and then use p[i][j] as before. Then, you will get sizeof p[i] = M*sizeof(int):
#include <stdio.h>
#include <stdlib.h>
#define M 6
int main(int argc, char *argv[])
{
int n = 4;
int (*p)[M] = malloc(n*sizeof *p);
printf("Size of int: %lu\n", sizeof(int));
printf("n = %d, M = %d\n", n, M);
printf("Size of p: %lu (=8 because pointer in 64bits = 8 bytes)\n", sizeof p);
printf("Size of *p: %lu (=M*sizeof(int) because each case is an array of length M)\n", sizeof *p);
printf("Size of p[0]: %lu (=M*sizeof(int) because each case is an array of length M)\n", sizeof p[0]);
// Assign
for (int i=0; i<n; i++) {
for (int j=0; j<M; j++) {
(p[i])[j] = i*10+j;
}
}
// Display
for (int i=0; i<n; i++) {
for (int j=0; j<M; j++) {
printf("%2d; ", (p[i])[j]);
}
printf("\n");
}
return 0;
}
which gives:
Size of int: 4
n = 4, M = 6
Size of p: 8 (=8 because pointer in 64bits = 8 bytes)
Size of *p: 24 (=M*sizeof(int) because each case is an array of length M)
Size of p[0]: 24 (=M*sizeof(int) because each case is an array of length M)
0; 1; 2; 3; 4; 5;
10; 11; 12; 13; 14; 15;
20; 21; 22; 23; 24; 25;
30; 31; 32; 33; 34; 35;

adding an element to an array using realloc

I'm trying to use realloc to add an element to an array after inputting characters.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int i, j, k;
int a = 1;
int* array = (int*) malloc(sizeof(int) * a);
int* temp;
for(i = 0;;i++)
{
scanf("%d", &j);
temp = realloc(array, (a + 1) * sizeof(int));
temp[i] = j;
if(getchar())
break;
}
for(k=0; k <= a; k++)
{
printf("%d", temp[k]);
}
}
When I run this little program, and if I enter for exemple : 2 3 4
it displays me: 20;
I know that memory hasn't been allocated properly, but I can't figure out the issue.
Thanks in advance.
Firstly:
int* array = (int*) malloc(sizeof(int) * a);
int* temp = array;
and
temp = realloc(temp, (a + 1) * sizeof(int));
because after call 'realloc' pointer passed as first argument may becomes invalid.
And of course 'realloc' called with second parameter equal 2 always.
By the way 'scanf' stops read your input string after first non-digit character. Read documentation for correctly usage functions. For example about scanf() or realloc().

Resources