1

I've been getting segmentation fault and I don't know why. I have a feeling that it's caused by the code under if(isPalindrome(str_array[i]) == 0) but I don't know which one and what to do about it.

P.S. I'm still a student so I would appreciate it if the suggestions do not go far from the level of code that I have here.

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

int isPalindrome(char check[]);

int main() {
    int array_size = 5, i;
    char *str_array[array_size], *palindrome_array[array_size], str_length[100];

    for(i = 0; i < array_size; i++) {
        printf("Enter word #%d: ", i+1);
        scanf("%[^\n]%*c", str_length); //"%[^\n]%*c : pattern matching - allows inputs to have spaces

        str_array[i] = (char*) malloc(sizeof(char) * strlen(str_length));
        strcpy(str_array[i],str_length); 

        if(strcmp(str_array[i],"exit") == 0) {
            break;
        }
    
        if(isPalindrome(str_array[i]) == 0) {
            palindrome_array[i] = (char*) malloc(sizeof(char) * strlen(str_length));
            strcpy(palindrome_array[i], str_length); 
            printf("'%s' is a palindrome \n", palindrome_array[i]);
        } else printf("'%s' is NOT a palindrome \n", str_array[i]);
    }


    //BONUS: prints all the palindrome strings inputted
    printf("Your palindrome words are: \n");
    for(i = 0; i < array_size; i++) {
        printf("%d.)%s \n", i+1, palindrome_array[i]);
    }

    return 0;
}


int isPalindrome(char check[]) {        // from string to individual characters
    int middle = strlen(check) / 2;     //gets the half of the string's length
    int length = strlen(check);

    for(int i = 0; i < middle; i++) {
        if(check[i] != check[length - i - 1]) {
            return 1;
        } 
    }
    return 0;
}   
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • `str_array` isn't needed. Or rather, it doesn't need to be an array. There's also the possibility that you don't initialize all pointers of `palindrome_array`. Keep a separate counter for `palindrome_array` instead of using `array_size`. Or make sure you initialize all pointers of the array. – Some programmer dude Jul 26 '22 at 14:19
  • _"but I don't know which one and what to do about it."_. These types of things are not hard to know. Learn to use a debugger. Learn to create a debuggable executable, and to run in debug mode so failures will result in information pointing directly to the line the error occurs on. – ryyker Jul 26 '22 at 16:30
  • 4
    Please do not vandalize or deface your question. This is not allowed per site rules that you agreed to on joining, and also it creates unnecessary extra work for those of us who help curate the site. – Hovercraft Full Of Eels Jul 26 '22 at 18:01
  • OT: the function: `strlen()` returns a `size_t` not a `int` – user3629249 Jul 28 '22 at 20:47

3 Answers3

1
str_array[i] = (char*) malloc(sizeof(char) * strlen(str_length));

You need one char more to accommodate the null terminating character.

        str_array[i] = malloc(sizeof(**str_array) * strlen(str_length) + 1);
        strcpy(str_array[i], str_length); 

You repeat this error in other places as well. You need to change all wrong allocations.

Some remarks:

  1. Do not cast result of malloc. If the code does not compile you use C++ compiler to compiler C code which is not good.
  2. Use objects instead of types in sizeof
0___________
  • 60,014
  • 4
  • 34
  • 74
1

Two problems. There are two occurrences of the
first problem. They are both the same, and are simply that you are not providing enough room for NULL terminator in your string allocations... The error is in this clause:

str_array[i] = (char*) malloc(sizeof(char) * strlen(str_length));
                                             ^^^^^^^^^^^^^^^^^^
    strcpy(str_array[i],str_length); 

Change it to :

 str_array[i] = malloc(strlen(str_length)+1);
                                         ^^
    strcpy(str_array[i],str_length);   

...to accommodate need for NULL character.

The same is true for the palindrome test:

palindrome_array[i] = malloc( strlen(str_length)+1);
                                                ^^
        strcpy(palindrome_array[i], str_length); 

Note - applies to both corrections above:

second problem occurs when at the end of the inputting of words, and the program attempts to output all palindromes, the array palindrome_array[i] was found to have one less element of array than needed. I will leave troubleshooting that problem to you, but Should you choose to use realloc()at some point, here is a discussion on how to do it correctly.

ryyker
  • 22,849
  • 3
  • 43
  • 87
1

There are two main drawbacks.

To allocate a memory for a string you need to reserve space for the terminating zero character '\0' of the string.

So you need to write for example

str_array[i] = (char*) malloc(sizeof(char) * ( strlen(str_length) + 1 ) );

Also the array palindrome_array was not initialized.

char *str_array[array_size], *palindrome_array[array_size], str_length[100];

As not all tested strings are palindromes then some elements of the array still stay uninitialized for some values of the index i due to this if statement

    if(isPalindrome(str_array[i]) == 0) {
        palindrome_array[i] = (char*) malloc(sizeof(char) * strlen(str_length));
        strcpy(palindrome_array[i], str_length); 
        printf("'%s' is a palindrome \n", palindrome_array[i]);
    } else printf("'%s' is NOT a palindrome \n", str_array[i]);

As a result this for loop

for(i = 0; i < array_size; i++) {
    printf("%d.)%s \n", i+1, palindrome_array[i]);
}

can invoke undefined behavior.

You need to declare a separate index for the array and to use it instead of the index i.

In fact the array str_array is just redundant. It is enough to use these two arrays.

char *palindrome_array[array_size], str_length[100];

The parameter of the function isPalindrome should be declared with the qualifier const

int isPalindrome( const char check[]);

because the passed string is not changed within the function. Also it is much better when the function returns a npn-zero integer when a string is a palindrome and zero otherwise.

In the call of scanf you should specify the maximum length of the input string and the conversion specifier c should be removed. For example

scanf( " %99[^\n]", str_length );

Also it is unclear why there is used the magic number 5 in your program.

I would write the program the following way

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

int isPalindrome( const char s[] )
{
    size_t i = 0, n = strlen( s );

    while (i < n / 2 && s[i] == s[n - i - 1]) ++i;

    return i == n / 2;
}

int main( void )
{
    char **p = NULL;
    size_t total = 0;
    size_t count = 0;

    while (1)
    {
        char s[100];

        printf( "Enter a word (to exit just press Enter): " );

        if (scanf( "%99[^\n]%*c", s ) != 1 || s[0] == '\0') break;

        ++total;

        if (isPalindrome( s ))
        {
            printf( "\"%s\" is a palindrome\n", s );
            char **tmp = realloc( p, ( count + 1 ) * sizeof( char * ) );

            if (tmp == NULL)
            {
                puts( "Memory allocation error. It is impossible to store the string." );
                break;
            }

            p = tmp;

            p[count] = malloc( strlen( s ) + 1 );

            if (p[count] == NULL )
            {
                puts( "Memory allocation error. It is impossible to store the string." );
                break;
            }

            strcpy( p[count], s );
            ++count;
        }
        else
        {
            printf( "\"%s\" is NOT a palindrome\n", s );
        }
    }

    printf( "\nAmong the entered %zu words there are %zu palindrome(s).\n", total, count );
    if (count != 0)
    {
        puts( "They are:" );
        for (size_t i = 0; i < count; i++)
        {
            printf( "\"%s\"\n", p[i] );
        }
    }

    for (size_t i = 0; i < count; i++)
    {
        free( p[i] );
    }
    free( p );
}

Its output might look like

Enter a word (to exit just press Enter): 1
"1" is a palindrome
Enter a word (to exit just press Enter): 12
"12" is NOT a palindrome
Enter a word (to exit just press Enter): 122
"122" is NOT a palindrome
Enter a word (to exit just press Enter): 1221
"1221" is a palindrome
Enter a word (to exit just press Enter): 12321
"12321" is a palindrome
Enter a word (to exit just press Enter):

Among the entered 5 words there are 3 palindrome(s).
They are:
"1"
"1221"
"12321"
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • @Jay I do not know how obj_size is obtained and why print_i is not increased in the loop. See the demonstration program in my answer. – Vlad from Moscow Jul 26 '22 at 15:53
  • hello, @Vlad from Mascow! Is it possible that you can explain what happens in the code step by step briefly. Because I don't understand some parts of it like how realloc, size_t, etc. fits into the code as they still were not discussed in our class. I know this is a huge ask, but I would really appreciate it if you can. Thank you :) – Steven Universe Jul 26 '22 at 17:04
  • @Jay The type size_t is an unsigned integer type that is the return type of the function strlen or the type of the value returned by the operator sizeof.. realloc reallocate memory. You could just use n array of pointers of the type char * of a fixed size and when a palindrome is found to allocate using malloc a character array and copy there a string. You need to use a separate counter for elements of the array that is incremented when a palindrome is added to the array. – Vlad from Moscow Jul 26 '22 at 17:32
  • Hello, last question. instead of '\0' how can you make it that when the user inputs "exit" the loop terminates? – Steven Universe Jul 26 '22 at 17:44
  • @Jay printf( "Enter a word (to exit just type \"exit\"): " ); if (scanf( "%99[^\n]%*c", s ) != 1 || strcmp( s, "exit ) == 0) break; – Vlad from Moscow Jul 26 '22 at 17:47