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.
Related
I was checking pointer to pointer, passing it without allocating. I want to allocate a[0]="something str" a[1]="some thing str" a[2]="something str" a[3]="something str" in pp function. Can I do this (allocating and filling with strcpy in pp function) and get it returned back to main?
This is my attempt:
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#define MAX_LEN 100
// float 3
void pp(char *arr, char *delimiter, char **a)
{
int i = 0;
*a = malloc(sizeof(char) * 10);
}
int main(int argc, void **argv)
{
char *arr = "1.77 1.65 1.56 5.555 6.1";
char **f;
pp(arr, " ", &f[0]);
}
I thought I could just allocate individual char * and then populate as strcpy(*(a+x),"something") but it causes segfaults at *a = malloc(sizeof(char) * 10);.
You have multiple bugs in your code.
You do not initialized f but access f[0].
You allocate memory for 10 single char but not for pointers in your function.
Also the overall approach is broken.
You could try like this:
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#define MAX_LEN 100
void pp(char *arr,char *delimiter,char ***a)
{
// TODO: Handle NULL pointers.
int i=0;
// TODO: Calculate number of strings using arr and delimiter...
int num = 10;
*a=malloc((num+1) * sizeof(**a));
for (int k = 0; k < num; k++)
{
(*a)[k] = malloc( 1+ length of string to copy) ;
strcpy((*a)[k], <string to copy>);
}
(*a)[num] = NULL; // indicate end of array.
}
int main(int argc,void **argv)
{
char *arr="1.77 1.65 1.56 5.555 6.1";
char **f;
pp(arr, " ", &f);
int i = 0;
while (f[i] != NULL)
{
printf("string #%d: %s\n", i, f[i]);
i++;
}
}
You should also think about a way how to report the number of found substrings back to the caller. In the example I added an extra pointer holding NULL to terminate the array.
For starters the header <malloc.h> is not a standard C header. Instead use header <stdlib.h>.
Aa for your task
yes that what I will eventually do. Basically array that holds float
then you can use the approach shown in the demonstration program below
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
size_t split( const char *s, const char *delim, double **a )
{
*a = NULL;
size_t n = 0;
for ( const char *p = s; p += strspn( p, delim ), *p != '\0'; )
{
++n;
p += strcspn( p, delim );
}
if ( n != 0 && ( *a = malloc( n * sizeof( double ) ) ) != NULL )
{
char *endptr;
for ( size_t i = 0; i < n; i++ )
{
( *a )[i] = strtod( s, &endptr );
s = endptr;
}
}
return n;
}
int main( void )
{
char *s= "1.77 1.65 1.56 5.555 6.1";
double *a;
size_t n = split( s, " \t", &a );
if ( a != NULL )
{
for ( size_t i = 0; i < n; i++ )
{
printf( "%.3f ", a[i] );
}
putchar( '\n' );
}
free( a );
}
The program output is
1.770 1.650 1.560 5.555 6.100
Actually the function can be more complicated because you will need to check that conversion to double were suvvessful.
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
I really do not know if it is the right title for my question, but I will try to explain my problem :
I'm working on a program which search all string permutes and saves those string in a char** array.
Everything looks fine, but the program takes too much time too finish and this happens because of realloc calls which are too many and takes too much time. I am talking about 13700 calls here:
for ( size_t i = 0; i < SIZE_2D; i++ ){ // SIZE_2D == 13700
multi[i] = calloc(LINELENGTH, sizeof(char));
}
It is possible to call realloc on char** in a single call ?
Like the example here :
#include <stdio.h>
#include <stdlib.h>
int main(void){
int *arr;
unsigned int row = 5, col = 10;
arr = malloc(sizeof *arr * row * col);
if(arr == NULL){
printf("Error, malloc\n");
exit(3);
}
free(arr);
}
This is the working code:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE_2D 13700
#define LINELENGTH 8
void swap (char *x, char *y);
void permute(char *arr, char *ptr, size_t i, size_t n);
int compare(const void *a, const void *b);
void resizeBuffer ( char **arr, size_t length );
void resultFound( char **multi, char *buffer, size_t length );
//char multi[20240][50] = {0};
int main(void){
char str[] = "abcdefg";
char *arr = calloc(100000, sizeof(char));
char *multi[14000];
//char **multi = calloc(10240, sizeof(char*));
for ( size_t i = 0; i < SIZE_2D; i++ ){
multi[i] = calloc(LINELENGTH, sizeof(char));
}
permute( arr, str, 0, strlen( str ) );
resizeBuffer ( &arr, strlen( arr ) + 1 );
resultFound(multi, arr, strlen( arr ) );
free( arr );
for ( size_t i = 0; i < SIZE_2D; i++ ){
free(multi[i]);
}
}
void resultFound( char **multi, char *buffer, size_t length ){
printf("ARR LENGTH = %zu\n", length);
size_t i = 0;
char *ptr = buffer;
size_t p = 0;
size_t a = 0;
char *tmp = calloc(length + 1, sizeof(char));
size_t count = 0;
while ( i < length ){
if ( ptr[i] == '\n' ){
if ( count != 0){
//printf("Line Found! <-> Line Length = %zu <-> TMP = %s\n",count, tmp);
strcpy(multi[a++], tmp);
memset(tmp, 0, length);
count = 0;
p = 0;
}else{
//printf("Empty Line Found, Ignore it\n\n");
}
}else{
count++;
tmp[p++] = ptr[i];
}
i++;
}
for (size_t l = 0 ; l < a ; l++ ){
printf("Multi[%zu]\t= %s\n",l , multi[l]);
}
free(tmp);
}
void swap (char *x, char *y){
char temp;
temp = *x;
*x = *y;
*y = temp;
}
void permute(char *arr, char *ptr, size_t i, size_t n){
size_t j;
static char prev[80] = "";
if (i == n){
if (strcmp(prev, ptr)) {
strcat (arr, ptr);
strcat (arr, "\n");
strcpy(prev, ptr);
}
}else{
for (j = i; j <= n; j++)
{
swap( (ptr + i), (ptr + j) );
permute(arr, ptr, i+1, n);
swap( (ptr + i), (ptr + j) );
}
}
}
void resizeBuffer ( char **buffer, size_t length ){
*buffer = realloc(*buffer, (length)* sizeof(char) );
}
I am trying to insert a string by replacing a substring in the (original) string with a new string (toInsert). The start parameter is the starting position of the substring I want to replace. Note: This is part of a larger program but I am just trying to get this function to work.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ROW 5
#define COLUMN 81
void insertString(char original[], int start, int length, char toInsert[]){
char buffer[COLUMN];
int i = 0;
for (i=0; i<strlen(original); ++i){
if (i>=start){
buffer[i] = toInsert[i];
}
else{
buffer[i] = original[i];
}
}
buffer[strlen(buffer)-1] = '\0';
printf("%s\n", buffer);
return;
}
int main()
{
char rep[COLUMN] = "very";
char sub[COLUMN] = "are";
char buf[ROW][COLUMN] = {
{"How are you doing"}
};
int len = strlen(sub);
int start = 4;
insertString(buf[0], start, len, rep);
return 0;
}
The problem is it only prints "How".
I want it to print "How very you doing"
Also, I have tried using strcpy but that just gives errors/warnings (something to do with pointers and I don't want to deal with pointers because I have not learned about them yet.)
Your function does not make great sense because it neither enlarge or shrink the original string though it has to do this.
And moreover it has undefined behavior due to this if statement because when i is equal to or greater than start you can access the memory beyond the string toInsert using the index i.
if (i>=start){
buffer[i] = toInsert[i];
}
It is simpler to write the function using standard C functions.
Here you are
#include <stdio.h>
#include <string.h>
char * replaceString( char *s1, size_t pos, size_t n, const char *s2 )
{
size_t n1 = strlen( s1 );
if ( pos < n1 )
{
size_t n2 = strlen( s2 );
if ( n != n2 )
{
memmove( s1 + pos + n2, s1 + pos + n, n1 - pos - n + 1 );
}
memcpy( s1 + pos, s2, n2 );
}
return s1;
}
int main(void)
{
{
char s1[100] = "ab1111cd";
const char *s2 = "22";
puts( replaceString( s1, 2, 4 , s2 ) );
}
{
char s1[100] = "ab11cd";
const char *s2 = "2222";
puts( replaceString( s1, 2, 2 , s2 ) );
}
{
char s1[100] = "ab11cd";
const char *s2 = "22";
puts( replaceString( s1, 2, 2 , s2 ) );
}
return 0;
}
The program output is
ab22cd
ab2222cd
ab22cd
If to insert this code block
{
char s1[100] = "How are you doing";
const char *s2 = "very";
puts( replaceString( s1, 4, 3 , s2 ) );
}
in the demonstrative program you will get the output
How very you doing
Is it possible to reverse a string in place without using strlen, using recursion and with this definition?
void reverse(char *s, int dim);
The only thing I could do was:
void reverse(char *s, int dim)
{
int a = dim;
int b = strlen(s) - 1 - dim;
if ((a - b) <= 0)
return;
swap(s[a], s[b]);
reverse(s, dim - 1);
}
But I would like to do that without using strlen and without defining a similar function. Is it possible?
Ciao. Come va?
As for me I would declare the function the following way
char * reverse( char *s, size_t n );
Here is a demonstrative program
#include <stdio.h>
char * reverse( char *s, size_t n )
{
if ( !( n < 2 ) )
{
char c = s[0];
s[0] = s[n-1];
s[n-1] = c;
reverse( s + 1, n - 2 );
}
return s;
}
int main( void )
{
char s[] = "Hello misiMe";
puts( s );
puts( reverse( s , sizeof( s ) - 1 ) );
}
The program output is
Hello misiMe
eMisim olleH