How to sort a struct using qsort? - c

I have a struct declared like this
struct data
{
char * Date;
char * String;
};
struct data **RegArray = NULL;
int ArrayCount = 0;
I add new items to the array this way:
struct data **tmp = ( struct data ** )realloc( RegArray, ( ArrayCount + 1 ) * sizeof( struct data * ) );
if ( tmp == NULL )
{
printf( "\nRealloc failed!" );
return;
}
RegArray = tmp;
RegArray[ ArrayCount ] = ( struct data * )malloc( sizeof **RegArray );
if ( RegArray[ ArrayCount ] == NULL )
{
printf( "\nMalloc failed!" );
return;
}
RegArray[ ArrayCount ]->Date = _strdup( cDate );
RegArray[ ArrayCount ]->String = _strdup( cString );
ArrayCount++;
The function which compares the values:
int CompareByDate( const void *elem1, const void *elem2 )
{
//return ( ( data* )elem1 )->Date > ( ( data* )elem2 )->Date ? 1 : -1;
return strcmp( ( ( data* )elem1 )->Date, ( ( data* )elem2 )->Date );
}//CompareByDate
And finally I call qsort like this:
qsort( RegArray, ArrayCount-1, sizeof( data ), CompareByDate );
The problem is, that the data won't be sorted.
So what am I doing wrong?
Thanks!

In your qsort call and comparison function, you forget that you're dealing with an "array" of pointers. The easiest change is to not use an array of pointers:
struct data *RegArray = NULL;
/* ... */
struct data *tmp = realloc( RegArray, ( ArrayCount + 1 ) * sizeof( struct data ) );
if ( tmp == NULL )
{
printf( "\nRealloc failed!" );
return;
}
RegArray = tmp;
RegArray[ ArrayCount ].Date = _strdup( cDate );
RegArray[ ArrayCount ].String = _strdup( cString );
ArrayCount++;
This will make your qsort call (and comparison function) work as they are shown in the question.
If you don't want to change the code as outlined above, you have to change the qsort call and comparison function:
qsort( RegArray, ArrayCount-1, sizeof( data * ), CompareByDate );
/* ... */
int CompareByDate( const void *elem1, const void *elem2 )
{
struct data **d1 = (struct data **) elem1;
struct data **d2 = (struct data **) elem2;
return strcmp((*d1)->Date, (*d2)->Date);
}

Related

Struct data not printing

For some reason the data I have added to my linked list is not printing.
It prints if I add the function PrintList right after adding or if I print it within a for loop with a set number but I want it to print after adding all the products and after breaking the while loop.
This is my code:
typedef struct SProducts
{
char *name;
struct SProducts *next;
}Products;
Products *Add(Products *list, char *file)
{
Products *el = (Products *) malloc(sizeof(Products));
if(el != NULL)
{
el->name = file;
el->next = list;
}
return el;
}
void PrintList(Products *list)
{
while(list != NULL)
{
printf("%s", list->name);
list = list->next;
}
}
int main(void){
Products *list = NULL;
char file[255];
while (fgets(file,sizeof(file),stdin) != NULL)
{
list = Add(list, file);
if (file[0] == '\n')
{
break;
}
}
PrintList(list);
}
You are always passing the same address of the first character of the local character array file.
list = Add(list, file);
So the last string that is stored in this array will be outputted for all nodes of the list.
You need to allocate dynamically a character array in each node that will store the passed string.
For example
#include <stdlib.h>
#include <string.h>
//...
Products * Add( Products *list, const char *file )
{
Products *el = malloc( sizeof( Products ) );
if ( el != NULL )
{
e1->name = malloc( strlen( file ) + 1 );
if ( e1->name != NULL ) strcpy( el->name, file );
el->next = list;
}
return el;
}
//...
while ( fgets( file, sizeof( file ), stdin ) != NULL && file[0] != '\n' )
{
file[ strcspn( file, "\n" ) ] = '\0';
Products *tmp = Add( list, file );
if ( tmp != NULL ) list = tmp;
}
Pay attention to that you need also at least write a function that will delete all the allocated memory of the list when it will not be required any more.

dequeueing function working with 2 queues encounters segfault?

The function below is supposed to dequeue a structure that is made of 2 queues. Each time we dequeue the first queue, its rear needs to become the front of the second queue. Essentially moving the first element in the second queue to the first queue to be its rear. I came up with the algorithm below:
int dequeue(queue* Q1,queue* Q2){
node* temp;
if(Q1->rear=NULL){
return 0;
}
if(count<3){
temp=Q1->front;
Q1->front=Q1->front->next;
free(temp);
count--;
return 1;
}
if(count>=3){
temp=Q1->front;
Q1->front=Q1->front->next;
free(temp);
Q1->rear->next=Q2->front;
Q1->rear=Q1->rear->next;
Q2->front=Q2->front->next;
Q1->rear->next=NULL;
if(Q2->front=NULL){
Q2->rear=NULL;
}
count--;
return 1;
}
}
It gives a segfault at Q1->rear->next=Q2->front;
is there an alternative way to achieve this?
For starters there is a typo in the condition of the if statement
if(Q2->front=NULL){
Q2->rear=NULL;
}
You are using assignment instead of comparison.
There is also a bug in this if statement
if(count<3){
temp=Q1->front;
Q1->front=Q1->front->next;
free(temp);
count--;
return 1;
}
q1-front after this statement
Q1->front=Q1->front->next;
can be equal to NULL. In this case you need to set also Q1->rare to NULL.
But in any case your approach with the if statements
if(count<3){
temp=Q1->front;
Q1->front=Q1->front->next;
free(temp);
count--;
return 1;
}
if(count>=3){
temp=Q1->front;
Q1->front=Q1->front->next;
free(temp);
//...
makes the code less clear and as it occurred error prone.
I would write the function the following way
int dequeue( queue *q1, queue *q2 )
{
int success = q1->front != NULL;
if ( success )
{
if ( q2->front != NULL )
{
q1->rear->next = q2->front;
q1->rear = q1->rear->next;
q2->front = q2->front->next;
if ( q2->front == NULL ) q2->rear = NULL;
q1->rear->next = NULL;
}
node *tmp = q1->front;
q1->front = q1->front->next;
if ( q1->front == NULL ) q1->rear = NULL;
free( tmp );
--count;
}
return success;
}
Pay attention to that it is a bad programming practice when a function depends on a global variable (I mean the variable count). You could avoid such a situation wrapping queues and the variable count in a structure.
Here is a demonstration program that shows the function in action.
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int data;
struct node *next;
} node;
typedef struct queue
{
node *front;
node *rear;
} queue;
size_t count;
int dequeue( queue *q1, queue *q2 )
{
int success = q1->front != NULL;
if ( success )
{
if ( q2->front != NULL )
{
q1->rear->next = q2->front;
q1->rear = q1->rear->next;
q2->front = q2->front->next;
if ( q2->front == NULL ) q2->rear = NULL;
q1->rear->next = NULL;
}
node *tmp = q1->front;
q1->front = q1->front->next;
if ( q1->front == NULL ) q1->rear = NULL;
free( tmp );
--count;
}
return success;
}
int push( queue *q, int data )
{
node *new_node = malloc( sizeof( node ) );
int success = new_node != NULL;
if ( success )
{
new_node->data = data;
new_node->next = NULL;
if ( q->rear == NULL )
{
q->front = new_node;
}
else
{
q->rear->next = new_node;
}
q->rear = new_node;
++count;
}
return success;
}
int empty( const queue *q )
{
return q->front == NULL;
}
int front( queue *q )
{
return q->front->data;
}
int main( void )
{
queue q1 = { .front = NULL, .rear = NULL };
queue q2 = { .front = NULL, .rear = NULL };
const int N = 10;
for ( int i = 0; i < N; i++ )
{
if ( i < N / 2 ) push( &q1, i );
else push( &q2, i );
}
while ( !empty( &q1 ) )
{
printf( "%d ", front( &q1 ) );
dequeue( &q1, &q2 );
}
putchar( '\n' );
for ( int i = 0; i < N; i++ )
{
if ( i < N / 2 ) push( &q1, i );
else push( &q2, i );
}
while ( !empty( &q1 ) )
{
printf( "%d ", front( &q1 ) );
dequeue( &q1, &q2 );
}
putchar( '\n' );
}
The program output is
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
There are the same code is executed two times to show that the function dequeue works correctly.

I want to use pointer

I have pointer like this => char* str={"you","we","they"};
I want to take 'we' or "they" .how is it posible ?
can you sy something about pointer ?
It seems that you mean something like the following
char *str[] = { "you", "we", "they" };
for ( size_t i = 0; i < sizeof( str ) / sizeof( *str ); i++ )
{
puts( str[i] );
}
Or
char *str[] = { "you", "we", "they" };
for ( size_t i = 0; i < sizeof( str ) / sizeof( *str ); i++ )
{
for ( char *p = str[i]; *p != '\0'; ++p ) putc( *p );
printf( "\n" );
}

hash table implementation code fails to run

I have developed the below hash table implementation code, but it fails to execute while trying to insert key,value pair.
I am very new to this concept and trying hard to fix this one.Any help would be greatly appreciated.
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <string.h>
#include<conio.h>
struct entry_s {
char *key;
char *value;
struct entry_s *next;
};
typedef struct entry_s entry_t;
struct hashtable_s {
int size;
struct entry_s **table;
};
typedef struct hashtable_s hashtable_t;
/* Create a new hashtable. */
hashtable_t *ht_create( int size ) {
hashtable_t *hashtable = NULL;
int i;
if( size < 1 ) return NULL;
/* Allocate the table itself. */
if( ( hashtable = malloc( sizeof( hashtable_t ) ) ) == NULL ) {
return NULL;
}
/* Allocate pointers to the head nodes. */
if( ( hashtable->table = malloc( sizeof( entry_t * ) * size ) ) == NULL ) {
return NULL;
}
for( i = 0; i < size; i++ ) {
hashtable->table[i] = NULL;
}
hashtable->size = size;
return hashtable;
}
/* Hash a string for a particular hash table. */
int ht_hash( hashtable_t *hashtable, char *key ) {
unsigned long int hashval=0;
int i = 0;
/* Convert our string to an integer */
while( hashval < ULONG_MAX && i < strlen( key ) ) {
hashval = hashval << 8;
hashval += key[ i ];
i++;
}
return hashval % hashtable->size;
}
/* Create a key-value pair. */
entry_t *ht_newpair( char *key, char *value ) {
entry_t *newpair=NULL;
if( ( newpair == malloc( sizeof( entry_t ) ) ) == NULL ) {
return NULL;
}
if( ( newpair->key = _strdup( key ) ) == NULL ) {
return NULL;
}
if( ( newpair->value = _strdup( value ) ) == NULL ) {
return NULL;
}
newpair->next = NULL;
return newpair;
}
/* Insert a key-value pair into a hash table. */
void ht_set( hashtable_t *hashtable, char *key, char *value ) {
int bin = 0;
entry_t *newpair = NULL;
entry_t *next = NULL;
entry_t *last = NULL;
bin = ht_hash( hashtable, key );
next = hashtable->table[ bin ];
while( next != NULL && next->key != NULL && strcmp( key, next->key ) > 0 ) {
last = next;
next = next->next;
}
/* There's already a pair. Let's replace that string. */
if( next != NULL && next->key != NULL && strcmp( key, next->key ) == 0 ) {
free( next->value );
next->value = _strdup( value );
/* Nope, could't find it. Time to grow a pair. */
} else {
newpair = ht_newpair( key, value );
/* We're at the start of the linked list in this bin. */
if( next == hashtable->table[ bin ] ) {
newpair->next = next;
hashtable->table[ bin ] = newpair;
/* We're at the end of the linked list in this bin. */
} else if ( next == NULL ) {
last->next = newpair;
/* We're in the middle of the list. */
} else {
newpair->next = next;
last->next = newpair;
}
}
}
/* Retrieve a key-value pair from a hash table. */
char *ht_get( hashtable_t *hashtable, char *key ) {
int bin = 0;
entry_t *pair;
bin = ht_hash( hashtable, key );
/* Step through the bin, looking for our value. */
pair = hashtable->table[ bin ];
while( pair != NULL && pair->key != NULL && strcmp( key, pair->key ) > 0 ) {
pair = pair->next;
}
/* Did we actually find anything? */
if( pair == NULL || pair->key == NULL || strcmp( key, pair->key ) != 0 ) {
return NULL;
} else {
return pair->value;
}
}
int main( int argc, char **argv ) {
hashtable_t *hashtable = ht_create( 65536 );
ht_set( hashtable, "key1", "john" );
ht_set( hashtable, "key2", "kris" );
ht_set( hashtable, "key3", "ricky" );
ht_set( hashtable, "key4", "mike" );
printf( "%s\n", ht_get( hashtable, "key1" ) );
printf( "%s\n", ht_get( hashtable, "key2" ) );
printf( "%s\n", ht_get( hashtable, "key3" ) );
printf( "%s\n", ht_get( hashtable, "key4" ) );
return 0;
}
Change
newpair == malloc( sizeof( entry_t ) ) to
newpair = malloc( sizeof( entry_t ) )
in ht_newpair

scrolling menu ( c code )

I want to create a menu with max 10 line window, and display in this window all items from a xml file ( containing more than 10 items), by scrolling up/down line in window to view all content of file.
Questions: How make this possible in my API (like in ncurses scroll menu):
"If the sub window given for a window is not big enough to show all the items, then the menu will be scrollable. When you are on the last item in the present list, if you send REQ_DOWN_ITEM, it gets translated into REQ_SCR_DLINE and the menu scrolls by one item. You can manually give REQ_SCR_ operations to do scrolling. Let's see how it can be done."
Part of my code for this feature:
static void menu( commands_t *cmd )
{
/* this display only first 10 line */
int i;
char string[ 128 ];
for( i = 0; i < 10; i++ ) {
snprintf( string, sizeof (string), "%s", list_get_name( cmd->listmgr, i ) );
menu_list_set_text( cmd->menu, i, string );
}
}
Currently, this function can display only the first 10 items from list.
A
B
C
D
E
-----------------
Line 01 | F |
Line 02 | G |
Line 03 | H |
Line 04 | I |
Line 05 | J |
Line 06 | K |
Line 07 | L |
Line 08 | M |
Line 09 | N |
Line 10 | O |
-----------------
P
Q
R
S
T
.......
Z
For this I try to create API capable to set text in menu line from list, move up/down cursor in menu but I don't now how to make to move lines up or down.
typedef struct list_info_s list_info_t;
struct list_info_s
{
int position;
char name[ 50 ];
list_info_t *next;
list_info_t *prev;
};
const list_info_t *list_get_list( list_mgr_t *mgr, int pos)
{
const list_info_t *tmp = mgr->first;
int i;
for (i = 0; tmp && i < pos; i++)
tmp = tmp->next;
return tmp;
}
const char *list_get_name( list_mgr_t *mgr, int position )
{
const list_info_t *list = list_get_list(mgr, position);
if( (list) && (*list->name) ) {
return list->name;
} else {
return 0;
}
}
TO MOVE UP/DOWN:
void commands_handle( commands_t *cmd, int prog_cmd )
{
switch( prog_cmd ) {
case MENU_UP:
cmd->menu_position = (cmd->menu_position + cmd->menu_size - 1) % (cmd->menu_size);
menu( cmd );
break;
case MENU_DOWN:
cmd->menu_position = (cmd->menu_position + 1) % (cmd->menu_size);
menu( cmd );
break;
return;
}
}
MENU:
static void menu( commands_t *cmd )
{
/* this display only first 10 line */
int i;
char string[ 128 ];
for( i = 0; i < 10; i++ ) {
snprintf( string, sizeof (string), "%s", list_get_name( cmd->listmgr, i ) );
menu_list_set_text( cmd->menu, i, string );
}
}
Windows of menu is for max 10 items lines because xml may contain a large number of items.
What programming options have to display all lines from file to be visible on menu by presing UP/DOWN button?
This is actual API for menu:
#define MENU_MAX 10
struct menu_s
{
char *name;
char text[ MENU_MAX ][ 128 ];
char arguments[ MENU_MAX ][ 128 ];
int commands[ MENU_MAX ];
char back_argument[ 128 ];
int back_command;
int numlines;
int cursor;
int defaultcursor;
};
menu_t *menu_new( const char *name )
{
menu_t *menu = malloc( sizeof( menu_t ) );
if( !menu ) {
return 0;
}
menu->numlines = 0;
menu->cursor = 0;
menu->defaultcursor = 0;
menu->name = strdup( name );
if( !menu->name ) {
free( menu );
return 0;
}
return menu;
}
void menu_delete( menu_t *menu )
{
free( menu->name );
free( menu );
}
void menu_reset_num_lines( menu_t *menu )
{
menu->numlines = 0;
}
void menu_set_text( menu_t *menu, int line, const char *text )
{
snprintf( menu->text[ line ], sizeof( menu->text[ 0 ] ), "%s", text );
if( line >= menu->numlines ) menu->numlines = line + 1;
}
void menu_set_enter_command( menu_t *menu, int line, int command,
const char *argument )
{
menu->commands[ line ] = command;
snprintf( menu->argum#define MENU_MAX 10
struct menu_s
{
char *name;
char text[ MENU_MAX ][ 128 ];
char arguments[ MENU_MAX ][ 128 ];
int commands[ MENU_MAX ];
char back_argument[ 128 ];
int back_command;
int numlines;
int cursor;
int defaultcursor;
};
menu_t *menu_new( const char *name )
{
menu_t *menu = malloc( sizeof( menu_t ) );
if( !menu ) {
return 0;
}
menu->numlines = 0;
menu->cursor = 0;
menu->defaultcursor = 0;
menu->name = strdup( name );
if( !menu->name ) {
free( menu );
return 0;
}
return menu;
}
void menu_delete( menu_t *menu )
{
free( menu->name );
free( menu );
}
void menu_reset_num_lines( menu_t *menu )
{
menu->numlines = 0;
}
void menu_set_text( menu_t *menu, int line, const char *text )
{
snprintf( menu->text[ line ], sizeof( menu->text[ 0 ] ), "%s", text );
if( line >= menu->numlines ) menu->numlines = line + 1;
}
void menu_set_enter_command( menu_t *menu, int line, int command,
const char *argument )
{
menu->commands[ line ] = command;
snprintf( menu->arguments[ line ], sizeof( menu->arguments[ 0 ] ),
"%s", argument );
}
void menu_set_back_command( menu_t *menu, int command,
const char *argument )
{
menu->back_command = command;
snprintf( menu->back_argument, sizeof( menu->back_argument ),
"%s", argument );
}
void menu_set_cursor( menu_t *menu, int cursor )
{
menu->cursor = cursor;
}
const char *menu_get_name( menu_t *menu )
{
return menu->name;
}
int menu_get_num_lines( menu_t *menu )
{
return menu->numlines;
}
const char *menu_get_text( menu_t *menu, int line )
{
return menu->text[ line ];
}
int menu_get_enter_command( menu_t *menu, int line )
{
return menu->commands[ line ];
}
const char *menu_get_enter_argument( menu_t *menu, int line )
{
return menu->arguments[ line ];
}
int menu_get_back_command( menu_t *menu )
{
return menu->back_command;
}
const char *menu_get_back_argument( menu_t *menu )
{
return menu->back_argument;
}
int menu_get_cursor( menu_t *menu )
{
return menu->cursor;
}
int menu_get_default_cursor( menu_t *menu )
{
return menu->defaultcursor;
}
I tried a ugly solution:
static void menu( commands_t *cmd )
{
int i;
for( i = 0; i < 10; i++ ) {
char string[ 128 ];
snprintf( string, sizeof (string), "%s", list_get_name( cmd->listmgr, i )
menu_list_set_text( cmd->menu, i, string );
int scroll;
for( scroll = 0; scroll < list_size; scroll++ ) {
if( cmd->curmenupos == 10 + scroll ) {
snprintf( string, sizeof (string), "%s", list_get_name( cmd->listmgr, i + scroll + 1 )
menu_list_set_text( cmd->menu, i, string );
}
}
}
}
where "cmd->curmenupos" is command to get menu line position and
"list_size" is number of items from xml
You can simplify your solution somewhat by using an array based implementation of a ring buffer and then only print your menu from the head/tail at the top left corner. Then scrolling simply becomes advancing the head/tail and overwrite the line that is disappearing with the new one. Using an array based implementation should be ok, as your line numbers is constant anyway.
Depending on how slow the IO is, your software may use less IO resources and hence improve performance, by some simple caching of the old lines. Keep in mind not to prematurely optimize This could be done by letting the ring buffer have more entries than lines on your screen, and then only overwrite when scrolling past a certain point.

Resources