I'm trying to do a function in C language that it's checking if a String is palindromic (read the same way from the begging to the end and backwards ) . So I use the puts() function to print the String backwards and after a number of elements (>7) it prints some unwanted characters.
My routine is :
void isPal ( char ptr[], int i){
char array[i];
int j=0,k=0;
int l = i-1;
for (j=0; j<i ; j++){
array[j] = ptr[l]; printf("%c\t", array[j] );
printf("Character :%c -> [%d]\n", array[j],l );
l--;
}
printf("\nThe upside string is : ");
puts(array);
for (k=0; k<i ; k++){
if ( array[k] != ptr[k]){
printf("\nNot palindromic!!!\n");
return;
}
}
printf("\nIS PALINDROMIC..\n");
}
The result is accurate but the printing isn't right . Why that ?
The created array does not contain a string because there is no the terminating zero in the array.
Also there is no need to define an auxiliary array to determine whether the passed string is a palindrome.
Creating a variable length array within the function is unsafe and can result in a stack overflow. Apart from this the user of the function can pass to the function the second argument less than or equal to 0. In this case the function will have undefined behavior.
The function should do only one thing i.e. to determine whether the passed string is a palindrome.
It is the caller of the function that will decide what message to output if any.
The function parameter that specifies the array should have the qualifier const because the passed string is not being changed in the function.
The function can be defined the following way
int isPal ( const char *s )
{
size_t n = strlen( s );
size_t i = 0;
while ( i < n / 2 && s[i] == s[n-i-1] ) ++i;
return i == n / 2;
}
Here is a demonstrative program.
#include <stdio.h>
#include <string.h>
int isPal ( const char *s )
{
size_t n = strlen( s );
size_t i = 0;
while ( i < n / 2 && s[i] == s[n-i-1] ) ++i;
return i == n / 2;
}
int main(void)
{
const char *s = "123454321";
printf( "The string \"%s\" is %sa palindrome.\n",
s, isPal( s ) ? "" : "not " );
return 0;
}
Its output is
The string "123454321" is a palindrome.
Just replace char array[i]; with following two lines:
char array[i+1];
array[i] = '\0';
puts() takes string as an argument. In c, string is basically a character array with '\0' at the end. So, when we add '\0' at the end of array[] it becomes a string and as a result puts() does not show any unpredictable behaviour.
Related
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;
}
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"
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:
Do not cast result of malloc. If the code does not compile you use C++ compiler to compiler C code which is not good.
Use objects instead of types in sizeof
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:
Casting return of malloc() is not necessary and generally not a good idea in C.
And sizeof(char) is always 1 by definition.
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.
The problem is that when I try to reverse a word, there are some words that prints out with unspecified and random characters. I tried to change the string size and the results change (some words make up random characters and some no)
#include <stdio.h>
#include <string.h>
#define LEN 20
void reverse( char w[LEN]);
int main() {
char word[LEN];
reverse(word);
return 0;
}
void reverse (char w[LEN]){
char rev[LEN];
int i,j;
fgets(w, LEN, stdin);
for (i = 0, j = strlen(w)-1; i < strlen(w); i++, j--){
rev[j] = w[i];
}
printf("%s\n", rev);
return;
}
An example of my problem is this:
Input: bathroom
Output: moorhtabp⬧⬧oz⬧
Every time I execute the program, with the same input the output changes.
You simply need to add a '\0' or 0 at the end of rev to terminate it.
for (i = 0, j = strlen(w)-1; i < strlen(w); i++, j--)
{
rev[j] = w[i];
}
rev[i] = 0;
There are a few errors:
fgets() add an newline \n at the end of the string.
You must add a string terminator (0 byte) after the last character.
(Lesser issue) Using strlen() in the loop condition will iterate over the string multiple times. It usually results in O(N^2) algorithms.
Fixes:
Variant A
Use scanf to parse a single word
scanf(" %19s", w)
The specifier %19s scans up to 19 characters and add NULL terminator to fix 20-char-long array
Variant B
Check if the last character of w is \n. If so, replace it with zero.
int L = strlen(w);
if (L > 0 && w[L - 1] == '\n') {
w[--L] = 0;
}
Just put
rev[i] = 0;
at the end.
Just iterate until j is negative, meaning it reached the "one before first" character and there is nothing more to do.
for (i = 0, j = L-1; j >= 0; i++, j--)
rev[j] = w[i];
For starters the call of the function
char word[LEN];
reverse(word);
does not make a sense because neither string is passed to the function. You passed an uninitialized character array.
The function should do only one thing: reverse the passed string.
So the call of fgets should be removed from the function and placed in main.
The function fgets can append the new line character '\n' to the entered string. You need to remove it.
Within the function reverse you forgot to append the terminating zero character '\0' to the reversed string. So this call
printf("%s\n", rev);
invokes undefined behavior.
Also the type of the returned value of the standard C function strlen is the unsigned integer type size_t. You should use this type instaed of the signed integer type int.
And this declaration of the function
void reverse( char w[LEN])
also does not make a great sense because the compiler will adjust it to the following declaration
void reverse( char *w)
and in general the user can pass to the function a string of any length that can be greater than the value LEN.
Below there is a demonstrative program that shows how the function can be written.
#include <stdio.h>
#include <string.h>
char * reverse( char *s )
{
for ( size_t i = 0, n = strlen( s ); i < n / 2; i++ )
{
char c = s[i];
s[i] = s[n - i - 1];
s[n - i - 1] = c;
}
return s;
}
int main(void)
{
enum { N = 20 };
char s[N];
fgets( s, N, stdin );
s[ strcspn( s, "\n" ) ] = '\0';
puts( s );
puts( reverse( s ) );
return 0;
}
If to enter string "Hello World!" then the program output will be
Hello World!
!dlroW olleH
I am blocked at solving a problem in the book.
The problem is:
read a word and output the string backwards, and output it backwards,
you should print the palindrome if it is the same as the original.
Also, do not use a library such as string.h, but include stdio.h
only.
So I created the code below.
#include <stdio.h>
int main()
{
char str[128];
char temp;
int leng = 0;
char a;
scanf("%s", str);
{
a = str;
}
while(str[leng] != '\0')
leng++;
for (int i = 0; i < leng/2; i++)
{
temp = str[i];
str[i] = str[leng - i - 1];
str[leng - i - 1] = temp;
}
printf("%s\n", str);
{
if (a == str)
printf("palindrome\n");
}
return 0;
}
The output in reverse order was easily solved, but I blocked in the process at printing palindrome. I tried to print the palindrome only when the input and output values are the same.
However, if (a == str) I used was a code to compare address values.
Also,I thought that it would be useful to implement strcmp as a loop, but I can not find a way to compare the input value with the output value using strcmp.
Is there a way to compare the input and output values in C? Or is there a way to make palindrome print only under certain circumstances (input = output)?
I am wondering if I can code the input value = output value in C exactly.
Note that my code prints the palindrome when the address values are the same. So I haven't seen yet :(
Here is a loosely written untested code that should resolve your issues.
char str[128];
if( fgets( str, 128, stdin ) )
{
/* I hate this but restriction on string.h
Calculate the size of this string */
size_t s_len = 0;
char *p = str;
for( ; *p && *p != '\n' ; p++ )
s_len++;
/* trim down nextLine characters */
if( p && *p == '\n' )
{
*p = '\0';
}
if( s_len == 0 )
{
/* Should never be the case here */
exit(0);
}
/* This should handle both cases of reversing and pallindrom */
int isPallindrom = 1; /* Lets Say Yes for now*/
for( size_t i = 0, j = s_len-1; i < j ; i ++, j -- )
{
if( str[i] != str[j] )
isPallindrom = 0; // Not a pallindrom
swap( str, i, j); // Write a swap function here
}
/* at this point you should have
1. a reversed string in a
2. based on isPallindrom value a confirmation if it really a pallindrom */
}
There are some fundamental errors in your code for instance
a = str;
if (a == str)
turn on warnings while compilation to catch these well before execution.
edit - swap for you.
void swap( char *s, size_t i, size_t j )
{
char t = s[i];
s[i] = s[j];
s[j] = t;
}
Use this function:
int compare(char *str1, char *str2)
{
while(*str1 && *str2){
if(*str1 == *str2){
str1++;
str2++;
}
else return (*str2 - *str1);
}
if(*str1)
return -1;
if(*str2)
return 1;
return 0;
}
Logic:
Until '\0' is encountered in one of the strings, check the character in either string. If the characters are equal, continue. Otherwise, return a negative number of the character in string1 > string2, or a positive number if the character in string1 < string2.
Once a '\0' is encountered, check if string1 has any more characters. If yes, it is the greater string, hence return a negative number.
If string1 doesn't have any more characters, check string2. If that too has no more characters, return 0. Otherwise return a positive number.
I am trying to make a program which takes in a input of "Hello" and outputs "olleH" from reversing the order of the characters. However I keep getting a segmentation fault and I don't understand why
#include <stdio.h>
#include<string.h>
int main()
{
int i;
int size;
char s[100],a[100];
printf("Enter the word you want to get reversed: ");
scanf("%s",s);
while(s[i]!='\0')
{
a[i]=s[i];
i++;
}
size=sizeof(s);
while(i<sizeof(s))
{
s[i]=a[size];
}
printf("The reversed string is : %s",s);
}
Another simple way to reverse string.
Try this:
while(s[++i]!='\0'); // find the size of string
while(i>=0)
a[j++] = s[--i]; // reverse the string
a[j]='\0';
printf("The reversed string is : %s",a);
This while loop
while(i<sizeof(s))
{
s[i]=a[size];
}
does not make sense because index i has a value that points to outside the entered string (provided that it was initially correctly initialized) and the loop is infinite because i is not changed (and was not initially initialized) in the loop and also the right hand expression of this statement
s[i]=a[size];
is always the same and again refers memory outside the array.
Take into account that neither function declared in <string.h> is used in the program. So the header may be removed.
The program can look the following way
#include <stdio.h>
#define N 100
int main()
{
char s[N], d[N];
printf( "Enter the word you want to get reversed: " );
fgets( s, N, stdin );
size_t n = 0;
while ( s[n] != '\0' && s[n] != '\n' ) n++;
for ( size_t i = 0; i != n; i++ ) d[i] = s[n-i-1];
d[n] = '\0';
printf( "The reversed string is : %s\n", d );
return 0;
}
You can reverse a string without using an auxiliary array. For example
#include <stdio.h>
#define N 100
int main()
{
char s[N];
printf( "Enter the word you want to get reversed: " );
fgets( s, N, stdin );
size_t n = 0;
while ( s[n] != '\0' && s[n] != '\n' ) n++;
s[n] = '\0';
for ( size_t i = 0; i < n / 2; i++ )
{
char c = s[i];
s[i] = s[n-i-1];
s[n-i-1] = c;
}
printf( "The reversed string is : %s\n", s );
return 0;
}
The problem is in this part:
size=sizeof(s);
while(i<sizeof(s))
{
s[i]=a[size];
}
sizeof(s) will be 100 whereas the string you read from input can be less than that -- which would be undefined if you access uninitialized parts of s. So, you want to use strlen() to get the actual size of the string and use it to reverse.
Notice that scanf() is unsafe as it's written (what if you input more than 100 chars?). Suggest using fgets() instead.
Im just starting to learn C programming and for exercise i found one task. First i have to scan in two strings. Then i have to compare them character by character and if there are any same characters i have to print out the amount of the same characters.
It has to be done with pointers. So lets i have "boat" and "ship" so the program would return 0. But if it were "boat" and "soap" it would return 2.
This is what i've got so far but when i run it it gives me errors. I put the errors in comments.
Thanks in advance for your help.
#include <stdio.h>
#include <string.h>
int number_of_same_characters(char *, char *);
int main()
{
char * first[100];
char * second[100];
int result = 0;
printf("Enter first string\n");
gets(*first);
printf("Enter second string\n");
gets(*second);
result = number_of_same_characters(*first, *second);
printf("%d\n", result);
return 0;
}
int number_of_same_characters(char *p, char *q){ //i get this error here - error: invalid type argument of unary ‘*’ (have ‘int’)
int counter = 0;
for(int j = 0; *p[j] != '\0' || *q[j] != '\0'; ++j){ //i get this error here - error: invalid type argument of unary ‘*’ (have ‘int’)
if(strcmp(*p[j], *q[j])){
++counter;
}
}
return counter;
}
Mainly you've got a lot of extra *'s littering the program. The variable declarations should be:
char first[100];
char second[100];
The input calls should be†:
gets(first);
gets(second);
The method call should be:
result = number_of_same_characters(first, second);
And finally there shouldn't be any dereferences in the for loop.
for(int j = 0; p[j] != '\0' || q[j] != '\0'; ++j){
if(strcmp(p[j], q[j])){
++counter;
}
}
That'll get you closer, though there are still a couple of problems. As a hint, the || operator is suspect, and you don't need to use strcmp.
† It's worth pointing out that gets() is a dangerous function that can lead to buffer overflows. It's okay to use when you're just starting out, but don't let it become a habit, and don't ever use it in production code!
You defined character arrays incorrectly and incorrectly are using operator *.
Try the following
#include <stdio.h>
#include <string.h>
#define N 100
int number_of_same_characters( const char *, const char * );
int main()
{
char first[N];
char second[N];
int result = 0;
size_t n;
printf( "Enter first string: ");
fgets( first, N, stdin );
n = strlen( first );
if ( first[n - 1] == '\n' ) first[n - 1] = '\0';
printf( "Enter second string: ");
fgets( second, N, stdin );
n = strlen( second );
if ( second[n - 1] == '\n' ) second[n - 1] = '\0';
result = number_of_same_characters( first, second );
printf( "%d\n", result );
return 0;
}
int number_of_same_characters( const char *p, const char *q )
{
int counter = 0;
int i;
for( i = 0; p[i] != '\0' && q[i] != '\0'; ++i )
{
if ( p[i] == q[i] ) ++counter;
}
return counter;
}
If to enter boat and soap then the output will be
2