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.

6
  • Yeah, I forgot to mention, it's not allowed to use string,h lib. Commented Feb 3, 2021 at 19:54
  • Don't forget to add a '\0' to the end of the new string (otherwise it cannot be called a string) Commented Feb 3, 2021 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. Commented Feb 3, 2021 at 19:57
  • Is it allowed to use ctype.h? Commented Feb 3, 2021 at 19:57
  • The ASCII character set has several apparently unwanted characters between 'A' and 'z' ('[', ']', ...) Commented Feb 3, 2021 at 19:57

2 Answers 2

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;
}

Sign up to request clarification or add additional context in comments.

1 Comment

if(s[i] >= 'A' && s[i] <= 'z') may return more than "small and big letters" (without getting into Klingon char sets...)
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

2 Comments

Suggestion: add protection for s parameter when NULL pointer is passed (possible null pointer derefence).
@GrzegorzSzpetkowski String functions never check whether a null pointer is passed. It is the responsibility of the user of the function to pass a non-null pointer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.