0

I have assignment that to use function char *slova(const char *s) which returns dynamically allocated string that is only made of small and big letters. It's forbidden to use string.h library.

char *slova(const char *s)
{
    char *new;
    int br = 0;
    new = (char *)malloc(sizeof(s));
    for (int i = 0; i != '\0'; i++)
        if(s[i] >= 'A' && s[i] <= 'z')
        {
            new[br] = s[i];
            br++;
        }
    return new;
}

I know there are some other characters other than small and big letters between A and z in ASCII code, so don't worry about that. For some reason this code doesn't work and I don't know why.

Pat. ANDRIA
  • 2,330
  • 1
  • 13
  • 27
qu4lizz
  • 317
  • 2
  • 12
  • Yeah, I forgot to mention, it's not allowed to use string,h lib. – qu4lizz Feb 03 '21 at 19:54
  • Don't forget to add a `'\0'` to the end of the `new` string (otherwise it cannot be called a string) – pmg Feb 03 '21 at 19:57
  • 2
    `sizeof(s)` will be size of a pointer. You can easily get string length without `strlen()`. Or you can use `realloc` to allocate the memory as you go. – 001 Feb 03 '21 at 19:57
  • Is it allowed to use `ctype.h`? – MikeCAT Feb 03 '21 at 19:57
  • The [ASCII character set](http://asciiset.com/) has several apparently unwanted characters between `'A'` and `'z'` (`'['`, '`]'`, ...) – pmg Feb 03 '21 at 19:57
  • Careful! `sizeof(s)` is much smaller than you expect here. It does not work as `strlen(s)` would do. You have to do that yourself. – Morten Jensen Feb 03 '21 at 20:18

2 Answers2

3
  • sizeof(s) will return not the buffer size but the size of the pointer s.
  • i != '\0' is wrong. This means i != 0 and prevent it from entering the loop because initial value of i is 0.
  • You forgot to terminate the resulting string by adding a terminating null-character.
  • Casting the result of malloc() in C is discouraged.

Fixed code:

char *slova(const char *s){
    char *new;
    int br = 0;

    // calculate the length
    for (int i = 0; s[i] != '\0'; i++)
        if(s[i] >= 'A' && s[i] <= 'z'){
            br++;
        }

    // allocate buffer
    new = malloc(br + 1);
    if (new == NULL) return NULL;

    // actually create the string
    br = 0;
    for (int i = 0; s[i] != '\0'; i++)
        if(s[i] >= 'A' && s[i] <= 'z'){
            new[br] = s[i];
            br++;
        }

    new[br] = '\0';
    return new;
}

MikeCAT
  • 73,922
  • 11
  • 45
  • 70
  • `if(s[i] >= 'A' && s[i] <= 'z')` may return more than "small and big letters" (without getting into Klingon char sets...) – pmg Feb 03 '21 at 20:08
3

Look carefully at your function declaration

char *slova(const char *s){
            ^^^^^^^^^^^^^

Its parameter has the pointer type const char *. Thus in this statement

new = (char *)malloc(sizeof(s));

the expression sizeof(s) yields the size of a pointer that usually is equal to 8 or 4 bytes depending on the used system. That is this expression does not provide the length of the passed string.

Also the body of this loop

for (int i = 0; i != '\0'; i++)

never gets the control because the condition i != '\0' at once evaluates to false because the variable i was initialized by zero.

The function can look the following way as it is shown in the demonstrative program below. It does not use functions from the header <string.h>.

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>

char * slova( const char *s )
{
    size_t n = 0;
    
    for ( const char *t = s; *t != '\0'; ++t )
    {
        if ( isalpha( ( unsigned char )*t ) ) ++n;
    }
    
    char * result = malloc( ( n + 1 ) *sizeof( char ) );
    
    if ( result != NULL )
    {
        char *p = result;
        for ( ; *s; ++s)
        {
            if ( isalpha( ( unsigned char )*s ) )
            {
                *p++ = *s;
            }
        }
        
        *p = '\0';
    }
    
    return result;
}   

int main(void) 
{
    const char *s = "H#e#l#l#o W#o#r#l#d";
    
    char *p = slova( s );
    
    if ( p ) puts( p );
    
    free( p );
    
    return 0;
}

The program output is

HelloWorld

If you are not allowed also to use functions from the header <ctype.h> then the function can look the following way as it is shown in the demonstrative program below.

#include <stdio.h>
#include <stdlib.h>

char * slova( const char *s )
{
    const char *upper_case = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    const char *lower_case = "abcdefghijklmnopqrstuvwxyz";
    
    size_t n = 0;
    
    for ( const char *t = s; *t != '\0'; ++t )
    {
        const char *letter = lower_case;
        
        if ( *t < lower_case[0] )
        {
            letter = upper_case;
        }
        
        while ( *letter && *letter < *t ) ++letter;
        
        if ( *letter == *t ) ++n;
    }
    
    char * result = malloc( ( n + 1 ) *sizeof( char ) );
    
    if ( result != NULL )
    {
        char *p = result;
        
        for ( ; *s; ++s)
        {
            const char *letter = lower_case;
            
            if ( *s < lower_case[0] )
            {
                letter = upper_case;
            }
            
            while ( *letter && *letter < *s ) ++letter;
            
            if ( *letter == *s )
            {
                *p++ = *s;
            }
        }
        
        *p = '\0';
    }
    
    return result;
}   

int main(void) 
{
    const char *s = "H#e#l#l#o W#o#r#l#d";
    
    char *p = slova( s );
    
    if ( p ) puts( p );
    
    free( p );
    
    return 0;
}

Again the program output is

HelloWorld
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335