qsort turns all values of array to null - c

I have a program which reads in the lines of a text file and stores them in linesArr, I have also defined a function compFunc which takes two strings as inputs, makes copies of them and converts the copies to lowercase before returning the value of strcmp(copy1, copy2). I am trying to use this function to sort linesArr into alphabetical order with qsort(linesArr, size, 255, compFunc. But the values in the array turn from {"Bob", "James", "Alice"} to {(null), (null), (null)}.
This is how linesArr is initialised.
char **linesArr = (char**)malloc(size*sizeof(char));
for (int i = 0; i < size; i++) {
linesArr[i] = (char*)malloc(255*sizeof(char));
}
And it it filled with values from the text using the file pointer fp
for (int i = 0; i < size; i++) {
fgets(line, 255, fp);
strcpy(linesArr[i], line);
}
Why is qsort deleting the values in the array?

For starters this memory allocation
char **linesArr = (char**)malloc(size*sizeof(char));
^^^^^
is incorrect, You need to write
char **linesArr = (char**)malloc(size*sizeof(char *));
^^^^^^
Secondly the call of qsort must look like
qsort(linesArr, size, sizeof( char * ), compFunc);
because the array pointed to by the pointer linesArr is an array of pointers.
Here is a demonstrative program.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int compFunc( const void *a, const void *b )
{
const char *s1 = *( const char ** )a;
const char *s2 = *( const char ** )b;
while ( *s1 && tolower( ( unsigned char )*s1 ) == tolower( ( unsigned char )*s2 ) )
{
++s1;
++s2;
}
return tolower( ( unsigned char )*s1 ) - tolower( ( unsigned char )*s2 );
}
int main(void)
{
enum { size = 3, len = 255 };
char **linesArr = malloc( size * sizeof( char * ) );
for ( size_t i = 0; i < size; i++ )
{
linesArr[i] = malloc( len * sizeof( char ) );
}
char line[len];
for ( size_t i = 0; i < size; i++ )
{
fgets( line, sizeof( line ), stdin );
line[ strcspn( line, "\n" ) ] = '\0';
strcpy( linesArr[i], line );
}
qsort( linesArr, size, sizeof( *linesArr ), compFunc );
for ( size_t i = 0; i < size; i++ )
{
puts( linesArr[i] );
}
for ( size_t i = 0; i < size; i++ )
{
free( linesArr[i] );
}
free( linesArr );
return 0;
}
The program output might look like
Bob
James
Alice
Alice
Bob
James

Related

I'm not making the comparison I am intending to

I am trying to write a program that compares strings by their length and sorts them with qsort. I have been able to make them sort alphabetically, now I'm trying to sort them by length. What am I doing wrong with my comparison method? I'm unsure about pointers and feel that issue lies there. Thanks
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int stringCmp(const void *str1, const void *str2); //Function prototype.
int main (int argc, char *argv[])
{
int i;
char **arr = malloc(argc * sizeof(char *));
printf("Original Args:\n");
for (i = 0; i < argc-1; i++){
arr[i] = argv[i+1];
printf("%s\n",arr[i]);
}
qsort(arr, argc-1, sizeof *arr, stringCmp);
printf("\nSorted Args:\n");
for (i = 0; i < argc-1; i++){
printf("%s\n", arr[i]);
}
free (arr);
return 0;
}
int stringCmp(const void *str1, const void *str2)
{
return strlen(str1) - strlen(str2);
// return strcmp(*(char **)str1,*(char**) str2);
}
As with the commented out call to strcmp, the pointers received by the function actually have type char ** so you need to cast to that type.
return strlen(*(char **)str1) - strlen(*(char **)str2);
It seems you need to allocate argc - 1 pointers instead of argc pointers
char **arr = malloc( ( argc - 1 ) * sizeof(char *));
As for the comparison function then it can be defined the following way
int cmp( const void *s1, const void *s2 )
{
size_t n1 = strlen( *( const char ** )s1 );
size_t n2 = strlen( *( const char ** )s2 );
return ( n2 < n1 ) - ( n1 < n2 );
}
Here is a demonstration program.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int cmp( const void *s1, const void *s2 )
{
size_t n1 = strlen( *( const char ** )s1 );
size_t n2 = strlen( *( const char ** )s2 );
return ( n2 < n1 ) - ( n1 < n2 );
}
int main(void)
{
char * s[] = { "12345", "1234", "123", "12", "1" };
const size_t N = sizeof( s ) / sizeof( *s );
for ( size_t i = 0; i < N; i++ )
{
printf( "%s ", s[i] );
}
putchar( '\n' );
qsort( s, N, sizeof( *s ), cmp );
for ( size_t i = 0; i < N; i++ )
{
printf( "%s ", s[i] );
}
putchar( '\n' );
}
The program output is
12345 1234 123 12 1
1 12 123 1234 12345
Pay attention to that to implements the comparison function like
return strlen(*(char **)str1) - strlen(*(char **)str2);
will be incorrect because values of an expression of the unsigned integer type size_t can not be negative. And conversion such a value to the type int results in undefined behavior.

How to make a strings array by using dynamic memory allocation in C?

I tried to do this:
char** arr_from_num(int num)
{
char** strings = (char**)malloc(num*sizeof(char*));
if (strings == NULL)
return 0;
for (int i = 1; i <= num; i++) {
strings[i-1] = (char*)malloc(9 * sizeof(char));
strings[i-1] = "FizzBuzz";
}
return strings;
}
But the function has a failure in doing this line: char** strings = (char**)malloc(num*sizeof(char*));
How can I do it in other way?
For starters the function produces numerous memory leaks. At first a memory is allocated and its address is assigned to a pointer
strings[i-1] = (char*)malloc(9 * sizeof(char));
and then the pointer is reassigned by the address of a string literal
strings[i-1] = "FizzBuzz";
The function can look for example the following way
char ** arr_from_num( size_t n )
{
const char data[] = "FizzBuzz";
char **strings = malloc( n * sizeof( char* ) );
if ( strings != NULL )
{
for ( size_t i = 0; i < n; i++ )
{
strings[i] = malloc( sizeof( data ) );
if ( strings[i] != NULL ) strcpy( strings[i], data );
}
}
return strings;
}
Alternatively the function can be defined the following way
char ** arr_from_num( size_t n, size_t m, const char *dummy )
{
char **strings = calloc( n, sizeof( char* ) );
if ( strings != NULL && m != 0 )
{
for ( size_t i = 0; i < n; i++ )
{
strings[i] = calloc( m, sizeof( char ) );
if ( strings[i] != NULL && dummy != NULL )
{
strncpy( strings[i], dummy, m - 1 );
}
}
}
return strings;
}
Here is a demonstrative program.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char ** arr_from_num( size_t n, size_t m, const char *dummy )
{
char **strings = calloc( n, sizeof( char* ) );
if ( strings != NULL && m != 0 )
{
for ( size_t i = 0; i < n; i++ )
{
strings[i] = calloc( m, sizeof( char ) );
if ( strings[i] != NULL && dummy != NULL )
{
strncpy( strings[i], dummy, m - 1 );
}
}
}
return strings;
}
int main(void)
{
size_t n = 10;
char **strings = arr_from_num( n, n, "FizzBuzz" );
if ( strings != NULL )
{
for ( size_t i = 0; i < n; i++ )
{
printf( "%zu: ", i );
if ( strings[i] == NULL )
{
printf( "%p\n", ( void * )strings[i] );
}
else
{
puts( strings[i] );
}
}
}
if ( strings != NULL )
{
for ( size_t i = 0; i < n; i++ ) free( strings[i] );
}
free( strings );
return 0;
}
The program output is
0: FizzBuzz
1: FizzBuzz
2: FizzBuzz
3: FizzBuzz
4: FizzBuzz
5: FizzBuzz
6: FizzBuzz
7: FizzBuzz
8: FizzBuzz
9: FizzBuzz
An array of strings is basically a 2D array where the first [] in the array syntax shows "how many strings" you have and the 2nd [] shows the length of each.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void main()
{
char **arr = (char**)malloc(3);
for (int i = 0;i < 3;i++)
{
arr[i] = malloc(sizeof("Fizzbuzz"));
strcpy(arr[i], "Fizzbuzz");
}
//printing
for (int i = 0;i < 3;i++)
{
printf("\n%s", arr[i]);
}
free(arr);
}
You have to allocate memory twice. Once for the number of strings and 2nd for the number of characters in the string. At the end of program you must free memory which you created using malloc function.

Would char * xx[401] create 401 char pointers or a pointer to a char[401]?

I need to create a character double pointer that will have 401 character arrays.
Will char *xx[401] work, or will I have to use malloc and friends? If so, how should I do it?
With
char *xx[401];
you are declaring an array of 401 pointers to char. All of them will need to be initialized to some other existing char array, for example in this way
char foo[20] = "Hello";
xx[107] = foo;
or malloc'ed, if they are intended to be a dynamically allocated array of strings.
If all these mallocs bother you, you can always define it statically
char xx[401][20+1] = { 0 };
/* Population of element at index 137 with a string defined somewhere else in the code: */
char str[] = "Hi guys";
strncpy(xx[123], str, 20);
(in this example every string will be of the fixed length of 20+1). But it will have to be a global variable: placing it in the stack wouldn't be the best solution.
To make it clear you can rewrite this declaration
char *xx[401];
like
char * ( xx[401] );
That is it is an array with 401 elements of the type char *.
A pointer to this array will look like
char * ( *pxx )[401] = &xx;
Pointer to the element of the array will look like
char ** pxx = xx;
If you want to allocate dynamically an array with 401 elements of the type char * then the code can look like
char ** pxx = malloc( 401 * sizeof( char * ) );
Here is a demonstrative program that shows how an array of pointers to character arrays can be dynamically allocated.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
enum { N = 2, M = 6 };
const char * hello[N] = { "Hello", "World" };
char **s = malloc( N * sizeof( char * ) );
for ( size_t i = 0; i < N; i++ )
{
s[i] = malloc( M );
strcpy( s[i], hello[i] );
}
for ( size_t i = 0; i < N; i++ )
{
if ( i != 0 ) putchar( ' ' );
printf( "%s", s[i] );
}
putchar( '\n' );
for ( size_t i = 0; i < N; i++ )
{
free( s[i] );
}
free( s );
return 0;
}
The program output is
Hello World

How to bubble sort an array with unknown length in C

I need help to write a code that gets an array of unknown size and bubble sort it, every word between the spaces, ( only one space)
for example
bad dba = abd abd;
I wrote a code that gets a known size of strings,and I try to modify it and I can't think of anything.
Thanks in advance.!
my code so far is:
gets(strB);
do
{
flag = 0;
for
(q = 0; 'dont know what to put here'-J ; q++) {
if
(strB[q] > strB[q + 1])
{
// Swap
temp2 = strB[q];
strB[q] = strB[q + 1];
strB[q + 1] = temp2;
flag = 1;
}
}
j++;
} while
(flag != 0);
puts(strB);
We beginners should help each other.:)
If I have understood correctly you need to sort each word delimited by white spaces within a string.
You should write two functions. The first function splits a string into substrings and call a bubble sort function for each substring. The second function is a bubble sort function.
It can be done the following way
#include <stdio.h>
#include <ctype.h>
void bubble_sort( char *first, char *last )
{
for ( size_t n = last - first, sorted = n; !( n < 2 ); n = sorted )
{
for ( size_t i = sorted = 1; i < n; i++ )
{
if ( first[i] < first[i-1] )
{
char c = first[i];
first[i] = first[i-1];
first[i-1] = c;
sorted = i;
}
}
}
}
char * sort( char *s )
{
for ( char *p = s; *p; )
{
while ( isspace( ( unsigned char )*p ) ) ++p;
if ( *p )
{
char *q = p;
while ( *p && !isspace( ( unsigned char )*p ) ) ++p;
bubble_sort( q, p );
}
}
return s;
}
int main(void)
{
char s[] = "bad dba";
puts( s );
puts( sort( s ) );
return 0;
}
The program output is
bad dba
abd abd
Take into account that the function gets is an unsafe function and is not supported any more by the C Standard. Instead use the C standard function fgets.
To remove the appended new line character by the function fgets use the following trick
#include <string.h>
//...
fgets( s, sizeof( s ), stdin );
s[ strcspn( s, "\n" ) ] = '\0';
//...

Parsing a string to individual words

I'm looking at writing a function that parses a given string input and separates the string into its constituents (as defined by one or more space characters).
Unfortunately, I have had no real experience with string parsing, so any help would be really appreciated!
Many thanks!
Take a look to strsep(3) too, since it is "intended as a replacement for the strtok() function."
https://www.freebsd.org/cgi/man.cgi?strsep(3)
The function can be declared and defined the following way as it is shown in the demonstrative program.
#include <stdio.h>
#include <ctype.h>
size_t string_parser( const char *input, char *word_array[] )
{
size_t n = 0;
while ( *input )
{
while ( isspace( ( unsigned char )*input ) ) ++input;
if ( *input )
{
word_array[n++] = ( char * )input;
while ( *input && !isspace( ( unsigned char )*input ) ) ++input;
}
}
return n;
}
#define N 10
int main(void)
{
char s[] = "Hello Sam Talbot. How do you do?";
char * word_array[N];
size_t n = string_parser( s, word_array );
for ( size_t i = 0; i < n; i++ ) puts( word_array[i] );
return 0;
}
Its output is
Hello Sam Talbot. How do you do?
Sam Talbot. How do you do?
Talbot. How do you do?
How do you do?
do you do?
you do?
do?
Another approach to defining the function is to allocate dynamically the array of words inside the function. In this case the function declaration can look like
size_t string_parser( const char *input, char ***word_array )
You should at first count the words using one loop and then in another loop fill the array of words.
For example
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
size_t string_parser( const char *input, char ***word_array)
{
size_t n = 0;
const char *p = input;
while ( *p )
{
while ( isspace( ( unsigned char )*p ) ) ++p;
n += *p != '\0';
while ( *p && !isspace( ( unsigned char )*p ) ) ++p;
}
if ( n )
{
size_t i = 0;
*word_array = malloc( n * sizeof( char * ) );
p = input;
while ( *p )
{
while ( isspace( ( unsigned char )*p ) ) ++p;
if ( *p )
{
const char *q = p;
while ( *p && !isspace( ( unsigned char )*p ) ) ++p;
size_t length = p - q;
( *word_array )[i] = ( char * )malloc( length + 1 );
strncpy( ( *word_array )[i], q, length );
( *word_array )[i][length] = '\0';
++i;
}
}
}
return n;
}
int main(void)
{
char s[] = "Hello Sam Talbot. How do you do?";
char ** word_array = NULL;
size_t n = string_parser( s, &word_array );
for ( size_t i = 0; i < n; i++ ) puts( word_array[i] );
for ( size_t i = 0; i < n; i++ ) free( word_array[i] );
free( word_array );
return 0;
}
The program output is
Hello
Sam
Talbot.
How
do
you
do?
Take a look at strtok, this does what you require.
You need to at least attempt this on your own.

Resources