Function in C to check if a string is a palindrome - c

The function should check if an input string is a palindrome. It should not be case sensitive, and must ignore every other character except letters and numbers. The thing I am having problems with is when the string is empty(that means only the spaces are elements of the string), and when the string has a lot of other characters, but no letters or numbers.
This is my code, and it works well, except in the cases stated above.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int is_it_palindrome(const char* str){
int lenght;
lenght=strlen(str);
const char *start=str+0;
const char *end=str+lenght-1;
while(start<end){
if(!isalnum(*start)){
start++;
}
else if(!isalnum(*end)){
end--;
}
else if(toupper(*start)==toupper(*end)){
start++;
end--;
}
else{
return 0;
}
}
return 1;
}
int main() {
printf ("%d", is_it_palindrome(" "));
printf ("%d", is_it_palindrome("a"));
printf ("%d", is_it_palindrome(",./!\n+_[]{}#"));
printf ("%d", is_it_palindrome(",./!\n+_A[]{}#"));
return 0;
}
The function returns 0 if it is not a palindrome, and 1 if it is a palindrome. So the output here should be 0 1 0 1, but I get 1 1 1 1. I really don't know how to rewrite this program to contain the conditions that I need. I would really appreciate the help.

A string containing no alphanumeric characters is not a palindrome according to your rules yet it doesn't ever reach return 0; cause you skip over non alpha numeric characters.
To check it you have to add a flag that tracks if you have any alpha numeric characters at all.
Additionally to detect the single alnum char I go to start <= end instead of start < end
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int is_it_palindrome(const char* str) {
int lenght;
int has_alnum = 0;
lenght=strlen(str);
const char* start = str + 0;
const char* end = str + lenght - 1;
while (start <= end) {
if (!isalnum(*start)) {
start++;
} else if (!isalnum(*end)) {
end--;
} else if (toupper(*start) == toupper(*end)) {
has_alnum = 1;
start++;
end--;
} else {
return 0;
}
}
return has_alnum;
}
int main(void) {
printf("%d", is_it_palindrome(" "));
printf("%d", is_it_palindrome("a"));
printf("%d", is_it_palindrome(",./!\n+_[]{}#"));
printf("%d", is_it_palindrome(",./!\n+_A[]{}#"));
return 0;
}

Related

Palindrome that ignores spaces and special characters and converts all uppercase letters in the string to lowercase

I'm going to make a palindrome which should ignore spaces and special characters and should convert all uppercase letters in the string to lowercase. I have done everything, but when I run my program, neither of these two functions work. Convert uppercase to lowercase and ignore all non-uppercase letters. Could any of you help me to solve what is the problem?
#include<stdio.h>
#define SIZE 1000
#include <ctype.h>
#include<string.h>
// function that checks if it is a palindrome
int isPalindrome(char inputString[]) {
int l = 0;
int r = strlen(inputString) - 1;
while (r > l)
{
// will check all letters are equal to each other
if (inputString[l++] != inputString[r--]) {
return 0;
}// return 0 if not palindrome
}
// palindrome
return 1;
}
// function that ignores all non - letters
int no_special_characters(char inputString[])
{
char temp[SIZE];
int temp_index = 0;
int abc = 0;
int r = strlen(inputString);
for (int i = 0; i < r; i++)
{
char abc = inputString[i];
if (isalpha(abc) != 0)
{
temp[temp_index++] = abc;
}
}
temp[temp_index] = '\0';
return isPalindrome(temp);
}
// function that converts uppercase letters to lowercase
void to_lower(char inputstring[]) {
int length = strlen(inputstring);
for (int i = 0; i < length; i++)
{
if (isupper(inputstring[i]))
inputstring[i] = tolower(inputstring[i]);
else if (islower(inputstring[i]))
inputstring[i] = toupper(inputstring[i]);
}
return 0;
}
int main(void) {
int try_again = 1;
int end_run = 0;
while (try_again == 1) {
int try_again;
char inputString[SIZE] = "";
printf("Enter a string to check if it is a palindrome!\n");
//Scans the input string.
scanf_s("%s", &inputString, SIZE);
//Sends the string to the isPalindrome function. //If the return value is 1(true), the if statement is executed, otherwise the else statement.
if (isPalindrome(inputString)) {
printf("That is a palindrome!\n");
}
else {
printf("This is not a palindrome!\n");
}
printf("Do you want to try again: 1 for yes 0 for No?");
scanf_s("%d", &try_again);
//Changes the value of running depending on whether you want to continue or not.
if (try_again != 1) {
end_run = 0;
}
}
return 0;
}
1 - Don't use scanf
You shouldn't use scanf to read input from the console, especially in a loop. I'm not an expert in scanf_s in particular, but that whole family of functions can cause weird bugs if you don't know how they work. I recommend you read this article, it explains it better that I can.
2 - Your loop doesn't work
You are defining try_again in function scope and then redefining it in block scope: they are two different variables.
Your code is essentially this:
int main(void) {
int try_again = 1;
while (try_again == 1) {
int try_again;
scanf_s("%d", &try_again);
}
}
Which will run forever, since the while loop is checking the first variable, while you are assigning to the second one. It should look more like this:
int main(void) {
int try_again = 1;
while (try_again == 1) {
// int try_again;
// ^^ Don't refefine - use the one already defined
try_again = some_function_to_read_input();
}
}
3 - to_lower doesn't actually convert to lowercase
It converts uppercase to lowercase and lowercase to uppercase. This means "Aa" becomes "aA", which is not a palindrome even though it should be by your definition.
The function doesn't need to return anything, since it changes the string in place. You can simply call it like this:
int isPalindrome(char inputString[]) {
to_lower(inputString);
// Rest of code
}
4 - You aren't calling no_special_characters
You simply aren't calling it. Either you do it in your main, something like:
// main
if (no_special_characters(inputString)) {
// Rest of code
}
Or you change it to return the modified string and call it from inside isPalindrome:
void no_special_characters(char inputString[]) {
// Remove all special characters, in place
}
int isPalindrome(char inputString[]) {
no_special_characters(inputString);
to_lower(inputString);
// Rest of code
}

C Program to Check for Palindrome String

I wrote two sample programs to check for a palindrome string. But in both I am getting output like, its not a palindrome number. What I am missing?
I strictly assume somehow code is executing my if statement and put flag in to 1. May be because of that length calculation. Anyone has a better idea?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
int main(void) {
setbuf(stdout,NULL);
char name[100];
int i,length,flag=0,k;
printf("Enter your name");
/*scanf("%s",name);*/
gets(name);
length=strlen(name);
for(i=0;i<=length-1;i++)
{
for(k=length-1;k>=0;k--)
{
if(name[i]!=name[k])
{
flag=1;
break;
}
}
}
if(flag==0)
{
printf("Give word is a palindrome");
}
if(flag==1)
{
printf("This is NOT a palindrome word");
}
return 0;
}
and
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
int main(void) {
setbuf(stdout,NULL);
char name[100];
int i,length,flag=0;
printf("Enter your name");
/*scanf("%s",name);*/
gets(name);
length=strlen(name);
for(i=0;i<=length/2;i++)
{
if(name[i]!=name[length-1])
{
flag=1;
}
}
if(flag==0)
{
printf("Give word is a palindrome");
}
if(flag==1)
{
printf("This is NOT a palindrome word");
}
return 0;
}
First Algorithm
The algorithm you are using in the first program involves comparing each letter to every other letter which does not help in determining if the number is a palindrome and it does not seem fixable.
Second Algorithm
The problem with the second approach, however, is you are always comparing name[i] to name[length]. Instead change it to length-i-1. This will start comparing from length-1 and decrement the length of the character by 1 for every next iteration:
for(i = 0;i <= length / 2;i++)
{
if(name[i] != name[length-i-1])
{
flag=1;
break;
}
}
gets() and buffer overflow
Do not use gets. This method is susceptible to a buffer overflow. If you enter a string longer than 100 characters, it will result in undefined behavior. Use fgets instead for deterministic behavior:
fgets(name, sizeof(name), stdin);
This takes in the size of the buffer and only reads up to sizeof(name) characters.
Full code
Ideally, you should consider wrapping the logic to check if the string is a palindrome in a function:
int is_palindrome(char*);
int main(void)
{
char name[100];
setbuf(stdout,NULL);
printf("Enter your name");
fgets(name, sizeof(name), stdin);
if(is_palindrome(name))
{
printf("The given word is a palindrome");
}
else
{
printf("This is NOT a palindrome word");
}
return 0;
}
int is_palindrome(char* name)
{
int length = strlen(name);
int flag = 0, i;
for(i = 0;i <= length / 2; i++)
{
if(name[i]!=name[length-i-1])
{
return 0;
}
}
return 1;
}
There is plenty wrong with both your attempts. I strongly suggest using a debugger to investigate how your code works (or doesn't).
Your first attempt performs length2 (incorrect) comparisons, when clearly only length / 2 comparisons are required. The second performs length / 2 comparisons but the comparison is incorrect:
name[i] != name[length-1] ;
should be:
name[i] != name[length - i - 1] ;
Finally you iterate exhaustively when you could terminate the comparison as soon as you know they are not palindromic (on first mismatch).
There may be other errors - to be honest I did not look further than the obvious, because there is a better solution.
Suggest:
#include <stdbool.h>
#include <string.h>
bool isPalindrome( const char* str )
{
bool is_palindrome = true ;
size_t rev = strlen( str ) - 1 ;
size_t fwd = 0 ;
while( is_palindrome && fwd < rev )
{
is_palindrome = (str[fwd] == str[rev]) ;
fwd++ ;
rev-- ;
}
return is_palindrome ;
}
In use:
int main()
{
const char* test[] = { "xyyx", "xyayx", "xyxy", "xyaxy" } ;
for( size_t t = 0; t < sizeof(test)/sizeof(*test); t++ )
{
printf("%s : %s palindrome\n", test[t],
isPalindrome( test[t] ) ? "Is" : "Is not" ) ;
}
return 0;
}
Output:
xyyx : Is palindrome
xyayx : Is palindrome
xyxy : Is not palindrome
xyaxy : Is not palindrome
Try this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char text[100];
int begin, middle, end, length = 0;
printf("enter the name: ");
scanf("%s",text);
while ( text[length] != '\0' ){
length++;}
end = length - 1;
middle = length/2;
for ( begin = 0 ; begin < middle ; begin++ ) {
if ( text[begin] != text[end] ) {
printf("Not a palindrome.\n");
break;
}
end--;
}
if( begin == middle )
printf("Palindrome.\n");
return 0;
}
The problem with the first piece of code is you are comparing it more than required, compare it with length-i-1.
The main problem with the second code is you are comparing it with only the last letter of a word.
Hope you understood your mistake

calculate sum of all numbers present in the string

I am solving this problem:
Given a string str containing alphanumeric characters, calculate sum
of all numbers present in the string.
Input:
The first line of input contains an integer T denoting the number of test cases. Then T test
cases follow. Each test case contains a string containing alphanumeric characters.
Output:
Print the sum of all numbers present in the string.
Constraints:
1 <= T<= 105
1 <= length of the string <= 105
Example:
Input:
4
1abc23
geeks4geeks
1abc2x30yz67
123abc
Output:
24
4
100
123
I have come up with the following solution:
#include <stdio.h>
#include <string.h>
int main() {
//code
int t,j;
char a[100000];
scanf("%d",&t);
while(t--)
{
int sum=0,rev=0,i=0,l;
scanf("%s",a);
l=strlen(a);
for(i=0;i<l;i++)
{
if (isdigit(a[i])){
while(isdigit(a[i])){
rev = rev *10 + (a[i]-48);
i++;
}
}
sum+=rev;
rev=0;
}
printf("%d\n",sum);
}
return 0;
}
This code is working fine.
BUT if loop termination condition is changed from i < l to a[i]!='\0', then code doesn't work. Why?
I would loop backwards over the string. No nested loops. Just take the 10s exponent as you move left
You have the length of the string, so there should be no reason to check for NUL char yourself
(untested code, but shows the general idea)
#include <math.h>
l=strlen(a);
int exp;
exp = 0;
for(i = l-1; i >= 0; i--)
{
if (isdigit(a[i])) {
rev = a[i]-48; // there are better ways to parse characters to int
rev = (int) pow(10, exp) * rev;
sum += rev; // only add when you see a digit
} else { exp = -1; } // reset back to 10^0 = 1 on next loop
exp++;
}
Other solutions include using regex to split the string on all non digit characters, then loop and sum all numbers
You will have to change the logic in your while loop as well if you wish to change that in your for loop condition because it's quite possible number exists at the end of the string as well, like in one of your inputs 1abc2x30yz67. So, correct code would look like:
Snippet:
for(i=0;a[i]!='\0';i++)
{
if (isdigit(a[i])){
while(a[i]!='\0' && isdigit(a[i])){ // this line needs check as well
rev = rev *10 + (a[i]-48);
i++;
}
}
sum+=rev;
rev=0;
}
On further inspection, you need the condition of i < l anyways in your while loop condition as well.
while(i < l && isdigit(a[i])){
Update #1:
To be more precise, the loop while(isdigit(a[i])){ keeps going till the end of the string. Although it does not cause issues in the loop itself because \0 ain't a digit, but a[i] != '\0' in the for loop condition let's you access something beyond the bounds of length of the string because we move ahead 1 more location because of i++ in the for loop whereas we already reached end of the string inside the inner while loop.
Update #2:
You need an additional check of a[i] == '\0' to decrement i as well.
#include <stdio.h>
#include <string.h>
int main() {
//code
int t,j;
char a[100000];
scanf("%d",&t);
while(t--)
{
int sum=0,rev=0,i=0,l;
scanf("%s",a);
l=strlen(a);
for(i=0;a[i]!='\0';i++)
{
if (isdigit(a[i])){
while(a[i] != '\0' && isdigit(a[i])){ // this line needs check as well
rev = rev *10 + (a[i]-48);
i++;
}
}
if(a[i] == '\0') i--; // to correctly map the last index in the for loop condition
sum+=rev;
rev=0;
}
printf("%d\n",sum);
}
return 0;
}
Update #3:
You can completely avoid the while loop as well as shown below:
#include <stdio.h>
#include <string.h>
int main() {
//code
int t,j;
char a[100005];
scanf("%d",&t);
while(t--)
{
int sum=0,rev=0,i=0,l;
scanf("%s",a);
l=strlen(a);
for(i=0;i<l;i++) {
if (isdigit(a[i])){
rev = rev * 10 + (a[i]-48);
}else{
sum += rev;
rev = 0;
}
}
printf("%d\n",sum + rev); // to also add last rev we captured
}
return 0;
}
Other answers have pointed out the correct loop conditions to ensure proper operation of your program.
If you are allowed to use library functions other than isdigit, I would recommend using strtol with the EndPtr parameter (output parameter that points to the character in the string that caused strtol to stop scanning a number):
char str[] = "1abc23def5678ikl";
int main()
{
char *pStop = str;
int n, accum = 0;
size_t len = strlen(str);
do
{
n = strtol(pStop, &pStop, 10);
pStop++;
if(n)
{
printf("%d\n", n);
accum += n;
}
}
while(pStop < &str[len]);
printf("Total read: %d\n", accum);
return 0;
}

How to check input in command line is integer in C?

I want the code to check input in command line is integer. i.e. 10b is not valid. I tried isdigit() but is not working? Thanks in advance.
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
int main(int argc, string argv[])
{
if (argc == 2)
{
int key = atoi(argv[1]);
if (isdigit(key))
{
printf("Success\n\%i\n", key);
exit(0);
}
}
printf("Usage: ./caesar key\n");
return 1;
}
Function isDigit checks if a single character is a digit, i.e. in the range between '0'..'9'. To check if a string is a number, I'd suggest to use function strtol.
long strtol(const char *str, char **str_end, int base ) converts a string str to an integral number and also sets the pointer str_end to the first character that took not part in the conversion any more. If you require that no characters must follow your number, then str_end must point to the string's end, i.e. to string termination character '\0':
#include <stdio.h>
#include <stdlib.h>
int isNumber(const char* str) {
if (!str || *str=='\0') { // NULL str or empty str: not a number
return 0;
}
char* endOfNum;
strtol(str,&endOfNum,10);
if (*endOfNum == '\0') { // string is at its end; everything in it was a valid part of the number
return 1;
} else {
return 0; // something that is not part of a number followed.
}
}
int main() {
const char* vals[] = {
"10b",
"-123",
"134 ",
" 345",
"",
NULL
};
for (int i=0; vals[i]; i++) {
printf("testing '%s': %d\n", vals[i], isNumber(vals[i]));
}
}
Output:
testing '10b': 0
testing '-123': 1
testing '134 ': 0
testing ' 345': 1
testing '': 0
Adapt the meaning of corner cases like empty strings or NULL-strings to your needs.
The isdigit function checks whether a single character represents a single digit. (numbers − 0 1 2 3 4 5 6 7 8 9).
In order to check if a string is an integer you could use a function like that. It will
bool isNumber(char number[])
{
int i = 0;
// only if you need to handle negative numbers
if (number[0] == '-')
i = 1;
for (; number[i] != 0; i++)
{
if (!isdigit(number[i]))
return false;
}
return true;
}
My first thought would be to use something like:
int inputvalue = 0;
if (sscanf(argv[i], "%d", &inputvalue) == 1)
{
// it's ok....
}
else
{
// not an integer!
}
or something like that. See http://www.cplusplus.com/reference/cstdio/sscanf/

strings to arrays then print in c

I am trying to take a user inputted string and look at each code to see if it appears in another string of strings. So far my code works.
If the word is successfully found then the alpha representation is to be added to an array that will eventually be printed, but only if all codes were found.
I am having issues with what gets stored in my array that is going to be printed.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef char *string;
typedef char *alpha;
int main(void)
{
string morse[4]={".-", "-...","----.", ".."};
string alpha[4]={"A", "B", "9", "I"};
char prntArr[50];
char *input;
char *hold;
input = malloc(200);
hold = malloc(50);
int i=0;
int j=0;
int ret;
int x;
int w=0;
int z=0;
printf("please enter a string\n");
scanf("%[^\n]",input);
do{
if (input[i] !=' ')
{
hold[j] = input[i];
j++;
}
else
{
hold[j]='\0';
for (x=0;x<4;x++)
{
printf("value of x %d\n",x);
ret = strcmp(morse[x], hold);
if (ret==0)
{
printf("%s\n",alpha[x]);
prntArr[w]=*hold;
w++;
x=4;
}
else
{
ret=1;
printf("invalid Morse code!");
}
}
j = 0;
}
i++;
}while(input[i] !='\0');
for (z=0;z<50;z++)
{
printf("%c",prntArr[z]);
}
return 0;
free(input);
}
The problem you asked about is caused by the way prntArr is used in the program. It really should be an array of character pointers into the alpha array. Instead, it's manipulated as an array of characters into which the first character of each morse code element is stored. And when it's printed, the variable that tracks how much of the array is used is simply ignored.
Another problem is that your code uses spaces to break the codes but there won't necessarily be a space at the end of the line so a code might get missed. In the program below, I switched out scanf() for fgets() which leaves a newline character on the end of the input which we can use, like space, to indicate the end of a code.
Other problems: you print the invalid Morse code message at the wrong point in the code and you print it to stdout instead of stderr; you remember to free input but forget to free hold; you put code after return that never gets called.
Below is a rework of your code that addresses the above problems along with some style issues:
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
int main(void)
{
char *morse[] = {".-", "-...", "----.", ".."};
char *alpha[] = {"A" , "B" , "9" , "I" };
char *print_array[50];
int print_array_index = 0;
char hold[50];
int hold_index = 0;
char input[200];
int i = 0;
printf("please enter a string: ");
fgets(input, sizeof(input), stdin);
while (input[i] !='\0') {
if (input[i] ==' ' || input[i] == '\n')
{
hold[hold_index] = '\0';
bool found = false;
for (int x = 0; x < sizeof(morse) / sizeof(char *); x++)
{
if (strcmp(morse[x], hold) == 0)
{
print_array[print_array_index++] = alpha[x];
found = true;
break;
}
}
if (!found)
{
fprintf(stderr, "invalid Morse code: %s\n", hold);
}
hold_index = 0;
}
else
{
hold[hold_index++] = input[i];
}
i++;
}
for (int x = 0; x < print_array_index; x++)
{
printf("%s ", print_array[x]);
}
printf("\n");
return 0;
}
SAMPLE RUNS
> ./a.out
please enter a string: ----. -... .- ..
9 B A I
>
> ./a.out
please enter a string: .- --- ..
invalid Morse code: ---
A I
>

Resources