Suffix array using qsort() and strcmp - arrays

I have the following code to create a sorted suffix array but there is simply no output. I run the program and it halts for 1-2secs and then exits.
The code is based off the c++ answer on the following website: https://www.geeksforgeeks.org/suffix-array-set-1-introduction/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
struct suffix
{
int index;
char *suff;
};
int cmp(const void *a, const void *b)
{
const struct suffix *a1 = a;
const struct suffix *b1 = b;
return strcmp(a1->suff, b1->suff) < 0? 1 : 0;
}
int *buildSuffixArray(char *txt, int n)
{
struct suffix suffixes[n];
for (int i = 0; i < n; i++)
{
suffixes[i].index = i;
suffixes[i].suff = (txt+i);
}
qsort(suffixes, n, sizeof(int), cmp);
int *suffixArr = (int*)malloc(n * sizeof(int));
for (int i = 0; i < n; i++)
{
suffixArr[i] = suffixes[i].index;
}
return suffixArr;
}
void printArr(int arr[], int n)
{
for (int i = 0; i < n; i++)
{
printf("%d", arr[i]);
}
printf("\n");
}
int main()
{
char txt[] = "banana";
int n = strlen(txt);
int *suffixArr = buildSuffixArray(txt, n);
printf("following is suffix array for %s\n", txt);
printArr(suffixArr, n);
return 0;
}
Since there is no output, I assume that the problem is within the 'buildSuffixArray' function, specifically with qsort. I have tried fixing it but had no luck. Any help would be appreciated.

Summarizing the comments in the question from Weather Vane and Jonathan Leffler:
OP is passing the wrong element size to qsort(). qsort(suffixes, n, sizeof(int), cmp); should be qsort(suffixes, n, sizeof suffixes[0], cmp);. (Weather Vane).
The cmp function must return a negative value if the first argument sorts before the second argument, zero if they sort equal, or a positive value if the first argument sorts after the second argument. OP's cmp function returns 1 if the first argument is less than the second argument, otherwise 0. This will screw up any sorting by qsort(). (Jonathan Leffler)
It appears that the cmp function written by OP was based on the C++ code from Suffix Array | Set 1 (Introduction). In particular, OP's return strcmp(a1->suff, b1->suff) < 0? 1 : 0; is based on the similar return strcmp(a.suff, b.suff) < 0? 1 : 0; in the C++ code. The problem is that the C++ code uses std::sort(), not qsort() and the rules for the return value of the comparison functions are different.
As Jonathan Leffler points out, it would be sufficient for OP's cmp function to return the value from strcmp() directly:
return strcmp(a->suff, b->suff);
OP's printArr() function prints the integers in the array with no separation between each number. The correction is trivial.

Related

C Segmentation Fault from function that returns the maximum of an array

I just have a function that finds out the maximum value of an array of integers, but I get a segmentation fault, which I can't find because the compiler doesn't show me the line of the error.
This is my C code:
#include <stdlib.h>
#include <stdio.h>
//Funktion ermittelt den größten Wert eines Arrays
int groesstesElement(int **arrayPointer){
int max = 0;
for (int i = 0; i < 3; i++) {
if (*arrayPointer[i]>max) {
max = *arrayPointer[i];
}
}
return max;
}
int main (int argc, char **argv) {
int array[4]={1,2,3,4};
int *ptr = array;
int z = groesstesElement(&ptr);
printf("%d\n", z);
return EXIT_SUCCESS;
}
I use macOS and VSC.
In C, array indexing [] has higher precedence than pointer de-referencing *: https://en.cppreference.com/w/c/language/operator_precedence
Some parentheses fix the segfault.
if ((*arrayPointer)[i]>max) {
max = (*arrayPointer)[i];
}
Due to the operators precedence, with
*arrayPointer[i]
you are telling your program:
Take the i-th element of the array arrayPointer and dereference it.
But arrayPointer is a pointer to int *, so all you get is the address of ptr (the int ** pointer defined from main) with an offset. When you finally dereference it you are likely accessing an invalid address, causing segmentation fault.
As already suggested by the main answer, the fix is done using parenthesis in order to apply the operators in the order you want:
(*arrayPointer)[i]
Secondary issues in the code
Even though with the correction above the program won't crash anymore, it won't work. Searching through the array with the loop
for (i = 0; i < 3; i++)
you won't include the last item in the search (index 3), skipping precisely the index that, in your example, contains the maximum value. You probably meant for (i = 0; i < 4; i++) or for (i = 0; i <= 3; i++).
Anyway, using magic numbers in the code (in this case the dimension of the array) is considered bad practice. A better solution would have been using a #define, but an even better solution would have been passing to the function the size of the array:
#include <stdlib.h>
#include <stdio.h>
#define ARR_SIZE 4
//Funktion ermittelt den größten Wert eines Arrays
int groesstesElement(int *arrayPointer, unsigned int arrSize){
int max = 0, i;
for (i = 0; i < arrSize; i++) {
if (arrayPointer[i]>max) {
max = arrayPointer[i];
}
}
return max;
}
int main (int argc, char **argv) {
int array[ARR_SIZE]={1,2,3,4};
int z = groesstesElement(array, ARR_SIZE);
printf("%d\n", z);
return EXIT_SUCCESS;
}
Please note how there's no need to use a double pointer anymore.

C - Why this function prints the array as NULL Strings?

I'm having a problem dealing with an array in C. You see, this is a portion of my code which basically reads a file and organizes coordinates of the vertices of parcels of the 3rd-levels administrive divisions in Portugal - which we call Freguesias. In this part of the exercise, I need to write the name of all 2rd-levels administrive divisions - Concelhos (which is already well defined in my code in the array Cartography cartography, that isn't the problem) that appear in the file.
I want to do a function that shows what Concelhos appear in the file and I want to write with this exact subfunctions and functions so I can change some things later, but for some reason it doesn't printf the strings in "command_list_concelhos", it just prints NULL strings. I don't know why this happens, specially since it does rightly so if I do a printf inside and outside the for in "read_string_concelhos".
Sorry if this question is wrongly explained, too big or just a small detail that I am missing, but I don't have a better way to explain it...
#define MAX_STRING 256
#define MAX_NAMES 50
typedef char String[MAX_STRING];
typedef struct {
String list[MAX_NAMES];
int n_strings;
} StringList;
int read_string_concelhos(StringList s ,Cartography cartography, int n)
{
int i, j=1;
strcpy (s.list[j-1], cartography[0].identification.concelho);
for ( i = 0 ; i < n ; i++){
if ( strcmp(cartography[i].identification.concelho, s.list[j-1]) != 0){
strcpy(s.list[j] , cartography[i].identification.concelho);
j++;
}
}
return j; // n_strings
}
void command_list_concelhos(Cartography cartography, int n)
{
StringList s;
s.n_strings = read_string_concelhos(s, cartography, n);
int i;
for(i = 0; i < s.n_strings; i++ )
{
printf("\n", s.list[i]);
}
}
Fail
How it should look like
int read_string_concelhos(StringList s ,Cartography cartography, int n)
should be changed to
int read_string_concelhos(StringList* s ,Cartography cartography, int n)
And inside the function int read_string_concelhos(StringList* s ,Cartography cartography, int n) { ... }, all s.list[...] should be changed to s->list[...]. In this way, parameter s is a pointer therefore strcmp would paste to s declared in command_list_concelhos which is the desired behaviour.

Sorting data from struct alphabetically? [duplicate]

Is there any library function available in C standard library to do sort?
qsort() is the function you're looking for. You call it with a pointer to your array of data, the number of elements in that array, the size of each element and a comparison function.
It does its magic and your array is sorted in-place. An example follows:
#include <stdio.h>
#include <stdlib.h>
int comp (const void * elem1, const void * elem2)
{
int f = *((int*)elem1);
int s = *((int*)elem2);
if (f > s) return 1;
if (f < s) return -1;
return 0;
}
int main(int argc, char* argv[])
{
int x[] = {4,5,2,3,1,0,9,8,6,7};
qsort (x, sizeof(x)/sizeof(*x), sizeof(*x), comp);
for (int i = 0 ; i < 10 ; i++)
printf ("%d ", x[i]);
return 0;
}
C/C++ standard library <stdlib.h> contains qsort function.
This is not the best quick sort implementation in the world but it fast enough and VERY
EASY to be used... the formal syntax of qsort is:
qsort(<arrayname>,<size>,sizeof(<elementsize>),compare_function);
The only thing that you need to implement is the compare_function, which takes in two
arguments of type "const void", which can be cast to appropriate data structure, and then
return one of these three values:
negative, if a should be before b
0, if a equal to b
positive, if a should be after b
1. Comparing a list of integers:
simply cast a and b to integers
if x < y,x-y is negative, x == y, x-y = 0, x > y, x-y is positive
x-y is a shortcut way to do it :)
reverse *x - *y to *y - *x for sorting in decreasing/reverse order
int compare_function(const void *a,const void *b) {
int *x = (int *) a;
int *y = (int *) b;
return *x - *y;
}
2. Comparing a list of strings:
For comparing string, you need strcmp function inside <string.h> lib.
strcmp will by default return -ve,0,ve appropriately... to sort in reverse order, just reverse the sign returned by strcmp
#include <string.h>
int compare_function(const void *a,const void *b) {
return (strcmp((char *)a,(char *)b));
}
3. Comparing floating point numbers:
int compare_function(const void *a,const void *b) {
double *x = (double *) a;
double *y = (double *) b;
// return *x - *y; // this is WRONG...
if (*x < *y) return -1;
else if (*x > *y) return 1; return 0;
}
4. Comparing records based on a key:
Sometimes you need to sort a more complex stuffs, such as record. Here is the simplest
way to do it using qsort library.
typedef struct {
int key;
double value;
} the_record;
int compare_function(const void *a,const void *b) {
the_record *x = (the_record *) a;
the_record *y = (the_record *) b;
return x->key - y->key;
}
For sure: qsort() is an implementation of a sort (not necessarily quicksort as its name might suggest).
Try man 3 qsort or have a read at http://linux.die.net/man/3/qsort
While not in the standard library exactly, https://github.com/swenson/sort has just two header files you can include to get access to a wide range of incredibly fast sorting routings, like so:
#define SORT_NAME int64
#define SORT_TYPE int64_t
#define SORT_CMP(x, y) ((x) - (y))
#include "sort.h"
/* You now have access to int64_quick_sort, int64_tim_sort, etc., e.g., */
int64_quick_sort(arr, 128); /* Assumes you have some int *arr or int arr[128]; */
This should be at least twice as fast as the standard library qsort, since it doesn't use function pointers, and has many other sorting algorithm options to choose from.
It's in C89, so should work in basically every C compiler.
try qsort in stdlib.h.
I think you are looking for qsort.
qsort function is the implementation of quicksort algorithm found in stdlib.h in C/C++.
Here is the syntax to call qsort function:
void qsort(void *base, size_t nmemb, size_t size,int (*compar)(const void *, const void *));
List of arguments:
base: pointer to the first element or base address of the array
nmemb: number of elements in the array
size: size in bytes of each element
compar: a function that compares two elements
Here is a code example which uses qsort to sort an array:
#include <stdio.h>
#include <stdlib.h>
int arr[] = { 33, 12, 6, 2, 76 };
// compare function, compares two elements
int compare (const void * num1, const void * num2) {
if(*(int*)num1 > *(int*)num2)
return 1;
else
return -1;
}
int main () {
int i;
printf("Before sorting the array: \n");
for( i = 0 ; i < 5; i++ ) {
printf("%d ", arr[i]);
}
// calling qsort
qsort(arr, 5, sizeof(int), compare);
printf("\nAfter sorting the array: \n");
for( i = 0 ; i < 5; i++ ) {
printf("%d ", arr[i]);
}
return 0;
}
You can type man 3 qsort in Linux/Mac terminal to get a detailed info about qsort.
Link to qsort man page
Use qsort() in <stdlib.h>.
#paxdiablo
The qsort() function conforms to ISO/IEC 9899:1990 (``ISO C90'').
There are several C sorting functions available in stdlib.h. You can do man 3 qsort on a unix machine to get a listing of them but they include:
heapsort
quicksort
mergesort
GNU qsort source in stdlib shows that it is quicksort.

Array pointers and functions

I have to write a C program to do the following:
Write a function that takes three arguments: a pointer to the first
element of a range in an array, a pointer to the element following
the end of a range in an array, and an int value. Have the function
set each element of the array to the int value.
My code is not working. Here is what I have so far. Any help is appreciated.
#include <stdio.h>
#include <iostream>
int listNumbers[3]{ 1,2,3 };
void Sorter(int *first, int * last, int *value);
int * first = &listNumbers[0];
int * last = &listNumbers[2];
int value;
int main() {
printf("your list numbers are:\n");
int i;
for (int i = 0; i < 3; ++i) {
printf("%d", listNumbers[i]);
}
printf("\n");
printf("enter an integer:\n");
scanf_s("%d", &value);
Sorter( first, last, &value);
printf("your new list numbers are:\n");
int j;
for (int j = 0; j < 3; ++j) {
printf("%d", listNumbers[j]);
}
printf("\n");
system("PAUSE");
return 0;
}
void Sorter(int *first, int * last, int *value) {
int i=0;
printf("value = %d\n", &value);
*first = value;
while (i <= *last) {
*(first + i) = value;
i++;
}
}
First, work out the different between the 2 pointers.
int count = last - first + 1;
The compiler will automatically divide by the size of an integer. We add 1 to make the range inclusive. Now just iterate through each element:
for (int i = 0; i < count; i++) {
first[i] = value;
}
Also, why are you passing the value as a pointer? This should just be a value.
void Sorter(int *first, int *last, int value) {
And when you call it...
Sorter(first, last, value);
Your Sorter function does not satisfy the problem criteria. The parameters are supposed to be two pointers into an array, and an int. Your function instead accepts three pointers.
You could nevertheless have made it implement at least the apparent spirit of the exercise, by using the value to which the third argument points as the fill value, but you don't do that. Instead you assign the pointer itself to each array element. That ought to at least elicit a warning from your compiler, and you ought not to be ignoring its warnings, especially when your code it not doing what you think it should.
Furthermore, the last pointer is expected to point to just past the last element to set, but you use it as if it points to an integer offset from the start pointer. This is almost the opposite of the previous problem: here, you need to use the pointer value itself, not the int to which it points.

Code crashes at the printf statement

The code runs until it reaches the statement:
printf("%d", sumOccur(input));
The code:
#include <stdio.h>
#include <stdlib.h>
int sumOccur(int A[]);
int main(){
int input[6] = {1,1,1,2,2,3};
printf("%d", sumOccur(input));
return 0;
}
int sumOccur(int A[]) {
int sum, i;
while(A[i]!='\0'){
sum += A[i];
i++;
}
return sum;
}
If I have made any silly mistakes please oblige.
It's not the printf() crashing. It's sumOccur(). Your array has no \0 value in it, so your while() never terminates and you end up in a near-infinite loop and run off the end of the array.
The array is an array of numbers, not a string, so there is no reason whatsoever to think there there would be a null-terminator on the values. null terminators are for strings, not arrays of numbers.
In your function int sumOccur you have two problems-
1. sum and i are not initialized just declared. Initialize both to 0 .
2. Also while(A[i]!='\0') ain't going to work as expected as your array doesn't have that value in it.
Your code invokes undefined behaviour: you access A[6] and subsequent inexistent entries in sumOccur trying to find a final 0 in the array, but you do not put one in the definition of input in the main function.
-------- cut here if you are not interested in gory implementation details --------
The array is allocated on the stack, very near the top since it is instantiated in the main function. Reading beyond the end until you find a 0 likely tries to read beyond the end of the stack pages and causes a segmentation fault.
Note that you are dealing with an int array,which means it normally won't contain '\0' character.To iterate over the array you need to specify number of elements.Here is the correct way :
#include <stdio.h>
#include <stdlib.h>
int sumOccur(int A[],size_t number_of_elemets);
int main(){
int input[6] = {1,1,1,2,2,3};
//Get the number of elements
size_t n = sizeof(input) / sizeof(int);
printf("%d", sumOccur(input,n));
return 0;
}
int sumOccur(int A[],size_t number_of_elements) {
int sum = 0;
size_t i = 0;
while( i < number_of_elements )
{
sum += A[i];
i++;
}
return sum;
}
You are iterating while A[i] != '\0' but there is no '\0' in the array and also you never initialize sum which is unlikely the cause for a crash but it could be.
You need to pass the number of elements in the array, like this
#include <stdio.h>
#include <stdlib.h>
int sumOccur(size_t count, const int *A);
int sumOccurCHQrlieWay(const int *A, size_t count);
int main()
{
int input[] = {1, 1, 1, 2, 2, 3};
printf("%d", sumOccur(sizeof(input) / sizeof(*input), input));
return 0;
}
int sumOccur(size_t count, const int *A)
{
int sum;
sum = 0;
for (size_t i = 0 ; i < count ; ++i)
sum += A[i];
return sum;
}
int sumOccurCHQrlieWay(const int *A, size_t count)
{
return sumOccur(count, A);
}

Resources