Check for palindrome using stack in C - c

I'm new to C, and I've been given a question to write a program to check palindrome words.
I did the following code, it gives an output. but the output is always "No". The idea of what I did in this code is, I first divided the string and pushed them into one stack (stacka). then pushed the rest of the letters to another stack(stackb). Then I pop both of those stacks and check whether the letter returning from each pop function(of stacka and stackb) is equal or not. if not it will return 0.
below is the code.
Thank you in advance. Have a nice day!.
#include <stdio.h>
#include <string.h>
char stacka[5];
char stackb[5];
int topa = -1;
int topb = -1;
void pusha(char e) {
topa++;
stacka[topa] = e;
}
void pushb(char e) {
topb++;
stackb[topb] = e;
}
char popa() {
char e = stacka[topa];
topa--;
return e;
}
char popb() {
char e = stackb[topb];
topb--;
return e;
}
int palindrome(char str[]) {
int i, length = strlen(str);
int mid = length / 2;
for (i = 0; i < mid; i++) {
pusha(str[i]);
}
if (length % 2 != 0) {
i++;
}
for (i = length - 1; i >= mid; i--) {
pushb(str[i]);
}
int f;
for (f = mid; f >= 0; f--) {
char ele1 = popa();
char ele2 = popb();
if (ele1 != ele2)
return 0;
}
return 1;
}
int main() {
char str[] = "madam";
if (palindrome(str)) {
printf("Yes");
} else
printf("No");
}

At a first glance, I have found the following issues in your code.
if(length % 2 !=0)
{
i++;
}
for(i=length-1;i>=mid;i--)
{
pushb(str[i]);
}
Your if block does not make any impact on the code and it is unnecessary as well. for loop has an issue as well which can cause your problem.
Let me elaborate a bit. Let's say your input is "madam" and according to your solution, first for loop is doing ok.
int mid=length/2;
for(i=0;i<mid;i++)
{
pusha(str[i]);
}
As your input is "madam" your value for mid would be 2. so, the first stack will contain the letter, 'm', 'a'. This is alright up to this.
In the second for loop there is a issue,
for(i=length-1;i>=mid;i--)
{
pushb(str[i]);
}
According to this stack will contain 'm', 'a', 'd'.
Now I would say the correction here according to me. First of all, you remove the first if block, then do this modification on the second for loop.
for(i=length-1;i>mid;i--)
{
pushb(str[i]);
}
Then finally in last for loop,
for(f=mid-1;f>=0;f--)
{
char ele1=popa();
char ele2=popb();
if(ele1!=ele2)
return 0;
}
I have not compiled and run the code with my given corrections. But I think this will help you to figure out the issues with your code.

First u change the condition of for loop in palindrome function.
for(i=length-1;i>mid;i--)
{
pushb(str[i]);
}

தலைவா எனக்கு ஆங்கிலம் நல்லா வராது.
First u change the condition of for loop in palindrome function.
for(i=length-1;i>mid;i--)
{
pushb(str[i]);
}
Your program is correct.

Related

Check if Char Array contains special sequence without using string library on Unix in C

Let‘s assume we have a char array and a sequence. Next we would like to check if the char array contains the special sequence WITHOUT <string.h> LIBRARY: if yes -> return true; if no -> return false.
bool contains(char *Array, char *Sequence) {
// CONTAINS - Function
for (int i = 0; i < sizeof(Array); i++) {
for (int s = 0; s < sizeof(Sequence); s++) {
if (Array[i] == Sequence[i]) {
// How to check if Sequence is contained ?
}
}
}
return false;
}
// in Main Function
char *Arr = "ABCDEFG";
char *Seq = "AB";
bool contained = contains(Arr, Seq);
if (contained) {
printf("Contained\n");
} else {
printf("Not Contained\n");
}
Any ideas, suggestions, websites ... ?
Thanks in advance,
Regards, from ∆
The simplest way is the naive search function:
for (i = 0; i < lenS1; i++) {
for (j = 0; j < lenS2; j++) {
if (arr[i] != seq[j]) {
break; // seq is not present in arr at position i!
}
}
if (j == lenS2) {
return true;
}
}
Note that you cannot use sizeof because the value you seek is not known at run time. Sizeof will return the pointer size, so almost certainly always four or eight whatever the strings you use. You need to explicitly calculate the string lengths, which in C is done by knowing that the last character of the string is a zero:
lenS1 = 0;
while (string1[lenS1]) lenS1++;
lenS2 = 0;
while (string2[lenS2]) lenS2++;
An obvious and easy improvement is to limit i between 0 and lenS1 - lenS2, and if lenS1 < lenS2, immediately return false. Obviously if you haven't found "HELLO" in "WELCOME" by the time you've gotten to the 'L', there's no chance of five-character HELLO being ever contained in the four-character remainder COME:
if (lenS1 < lenS2) {
return false; // You will never find "PEACE" in "WAR".
}
lenS1minuslenS2 = lenS1 - lenS2;
for (i = 0; i < lenS1minuslenS2; i++)
Further improvements depend on your use case.
Looking for the same sequence among lots of arrays, looking for different sequences always in the same array, looking for lots of different sequences in lots of different arrays - all call for different optimizations.
The length and distribution of characters within both array and sequence also matter a lot, because if you know that there only are (say) three E's in a long string and you know where they are, and you need to search for HELLO, there's only three places where HELLO might fit. So you needn't scan the whole "WE WISH YOU A MERRY CHRISTMAS, WE WISH YOU A MERRY CHRISTMAS AND A HAPPY NEW YEAR" string. Actually you may notice there are no L's in the array and immediately return false.
A balanced option for an average use case (it does have pathological cases) might be supplied by the Boyer-Moore string matching algorithm (C source and explanation supplied at the link). This has a setup cost, so if you need to look for different short strings within very large texts, it is not a good choice (there is a parallel-search version which is good for some of those cases).
This is not the most efficient algorithm but I do not want to change your code too much.
size_t mystrlen(const char *str)
{
const char *end = str;
while(*end++);
return end - str - 1;
}
bool contains(char *Array, char *Sequence) {
// CONTAINS - Function
bool result = false;
size_t s, i;
size_t arrayLen = mystrlen(Array);
size_t sequenceLen = mystrlen(Sequence);
if(sequenceLen <= arrayLen)
{
for (i = 0; i < arrayLen; i++) {
for (s = 0; s < sequenceLen; s++)
{
if (Array[i + s] != Sequence[s])
{
break;
}
}
if(s == sequenceLen)
{
result = true;
break;
}
}
}
return result;
}
int main()
{
char *Arr = "ABCDEFG";
char *Seq = "AB";
bool contained = contains(Arr, Seq);
if (contained)
{
printf("Contained\n");
}
else
{
printf("Not Contained\n");
}
}
Basically this is strstr
const char* strstrn(const char* orig, const char* pat, int n)
{
const char* it = orig;
do
{
const char* tmp = it;
const char* tmp2 = pat;
if (*tmp == *tmp2) {
while (*tmp == *tmp2 && *tmp != '\0') {
tmp++;
tmp2++;
}
if (n-- == 0)
return it;
}
tmp = it;
tmp2 = pat;
} while (*it++ != '\0');
return NULL;
}
The above returns n matches of substring in a string.

Understanding returning values functions C

I'm trying to understand how the return value of a function works, through the following program that has been given to me,
It goes like this :
Write a function that given an array of character v and its dim, return the capital letter that more often is followed by its next letter in the alphabetical order.
And the example goes like : if I have the string "B T M N M P S T M N" the function will return M (because two times is followed by N).
I thought the following thing to create the function:
I'm gonna consider the character inserted into the array like integer thank to the ASCII code so I'm gonna create an int function that returns an integer but I'm going to print like a char; that what I was hoping to do,
And I think I did, because with the string BTMNMPSTMN the function prints M, but for example with the string 'ABDPE' the function returns P; that's not what I wanted, because should return 'A'.
I think I'm misunderstanding something in my code or into the returning value of the functions.
Any help would be appreciated,
The code goes like this:
#include <stdio.h>
int maxvolte(char a[],int DIM) {
int trovato;
for(int j=0;j<DIM-1;j++) {
if (a[j]- a[j+1]==-1) {
trovato=a[j];
}
}
return trovato;
}
int main()
{
int dim;
scanf("%d",&dim);
char v[dim];
scanf("%s",v);
printf("%c",maxvolte(v,dim));
return 0;
}
P.S
I was unable to insert the value of the array using in a for scanf("%c,&v[i]) or getchar() because the program stops almost immediately due to the intepretation of '\n' a character, so I tried with strings, the result was achieved but I'd like to understand or at least have an example on how to store an array of character properly.
Any help or tip would be appreciated.
There are a few things, I think you did not get it right.
First you need to consider that there are multiple pairs of characters satisfying a[j] - a[j+1] == -1
.
Second you assume any input will generate a valid answer. That could be no such pair at all, for example, ACE as input.
Here is my fix based on your code and it does not address the second issue but you can take it as a starting point.
#include <stdio.h>
#include <assert.h>
int maxvolte(char a[],int DIM) {
int count[26] = {0};
for(int j=0;j<DIM-1;j++) {
if (a[j] - a[j+1]==-1) {
int index = a[j] - 'A'; // assume all input are valid, namely only A..Z letters are allowed
++count[index];
}
}
int max = -1;
int index = -1;
for (int i = 0; i < 26; ++i) {
if (count[i] > max) {
max = count[i];
index = i;
}
}
assert (max != -1);
return index + 'A';
}
int main()
{
int dim;
scanf("%d",&dim);
char v[dim];
scanf("%s",v);
printf("answer is %c\n",maxvolte(v,dim));
return 0;
}
#include <stdio.h>
int maxvolte(char a[],int DIM) {
int hold;
int freq;
int max =0 ;
int result;
int i,j;
for(int j=0; j<DIM; j++) {
hold = a[j];
freq = 0;
if(a[j]-a[j+1] == -1) {
freq++;
}
for(i=j+1; i<DIM-1; i++) { //search another couple
if(hold==a[i]) {
if(a[i]-a[i+1] == -1) {
freq++;
}
}
}
if(freq>max) {
result = hold;
max=freq;
}
}
return result;
}
int main()
{
char v[] = "ABDPE";
int dim = sizeof(v) / sizeof(v[0]);
printf("\nresult : %c", maxvolte(v,dim));
return 0;
}

Count of similar characters without repetition, in two strings

I have written a C program to find out the number of similar characters between two strings. If a character is repeated again it shouldn't count it.
Like if you give an input of
everest
every
The output should be
3
Because the four letters "ever" are identical, but the repeated "e" does not increase the count.
For the input
apothecary
panther
the output should be 6, because of "apther", not counting the second "a".
My code seems like a bulk one for a short process. My code is
#include<stdio.h>
#include <stdlib.h>
int main()
{
char firstString[100], secondString[100], similarChar[100], uniqueChar[100] = {0};
fgets(firstString, 100, stdin);
fgets(secondString, 100, stdin);
int firstStringLength = strlen(firstString) - 1, secondStringLength = strlen(secondString) - 1, counter, counter1, count = 0, uniqueElem, uniqueCtr = 0;
for(counter = 0; counter < firstStringLength; counter++) {
for(counter1 = 0; counter1 < secondStringLength; counter1++) {
if(firstString[counter] == secondString[counter1]){
similarChar[count] = firstString[counter];
count++;
break;
}
}
}
for(counter = 0; counter < strlen(similarChar); counter++) {
uniqueElem = 0;
for(counter1 = 0; counter1 < counter; counter1++) {
if(similarChar[counter] == uniqueChar[counter1]) {
uniqueElem++;
}
}
if(uniqueElem == 0) {
uniqueChar[uniqueCtr++] = similarChar[counter];
}
}
if(strlen(uniqueChar) > 1) {
printf("%d\n", strlen(uniqueChar));
printf("%s", uniqueChar);
} else {
printf("%d",0);
}
}
Can someone please provide me some suggestions or code for shortening this function?
You should have 2 Arrays to keep a count of the number of occurrences of each aplhabet.
int arrayCount1[26],arrayCount2[26];
Loop through strings and store the occurrences.
Now for counting the similar number of characters use:
for( int i = 0 ; i < 26 ; i++ ){
similarCharacters = similarCharacters + min( arrayCount1[26], arrayCount2[26] )
}
There is a simple way to go. Take an array and map the ascii code as an index to that array. Say int arr[256]={0};
Now whatever character you see in string-1 mark 1 for that. arr[string[i]]=1; Marking what characters appeared in the first string.
Now again when looping through the characters of string-2 increase the value of arr[string2[i]]++ only if arr[i] is 1. Now we are tallying that yes this characters appeared here also.
Now check how many positions of the array contains 2. That is the answer.
int arr[256]={0};
for(counter = 0; counter < firstStringLength; counter++)
arr[firstString[counter]]=1;
for(counter = 0; counter < secondStringLength; counter++)
if(arr[secondString[counter]]==1)
arr[secondString[counter]]++;
int ans = 0;
for(int i = 0; i < 256; i++)
ans += (arr[i]==2);
Here is a simplified approach to achieve your goal. You should create an array to hold the characters that has been seen for the first time.
Then, you'll have to make two loops. The first is unconditional, while the second is conditional; That condition is dependent on a variable that you have to create, which checks weather the end of one of the strings has been reached.
Ofcourse, the checking for the end of the other string should be within the first unconditional loop. You can make use of the strchr() function to count the common characters without repetition:
#include <stdio.h>
#include <string.h>
int foo(const char *s1, const char *s2);
int main(void)
{
printf("count: %d\n", foo("everest", "every"));
printf("count: %d\n", foo("apothecary", "panther"));
printf("count: %d\n", foo("abacus", "abracadabra"));
return 0;
}
int foo(const char *s1, const char *s2)
{
int condition = 0;
int count = 0;
size_t n = 0;
char buf[256] = { 0 };
// part 1
while (s2[n])
{
if (strchr(s1, s2[n]) && !strchr(buf, s2[n]))
{
buf[count++] = s2[n];
}
if (!s1[n]) {
condition = 1;
}
n++;
}
// part 2
if (!condition ) {
while (s1[n]) {
if (strchr(s2, s1[n]) && !strchr(buf, s1[n]))
{
buf[count++] = s1[n];
}
n++;
}
}
return count;
}
NOTE: You should check for buffer overflow, and you should use a dynamic approach to reallocate memory accordingly, but this is a demo.

While splitting one char array into array of char arrays, first array always displayed as random chars

I am doing a school exercise and it's asking us to split a string(character array) into multiple character arrays. A string input like this
"asdf qwerty zxcv"
should result in an array of characters arrays like this
"asdf","qwerty","zxcv"
While I am testing the code, no matter what strings I entered as the argument of my function, the first string printed out would always be some random characters, while the rest are as expected.
"02�9�","qwerty","zxcv"
Besides, my code worked fine in online compilers, which I saved here. I also tested in OnlineGDB, in which the code worked pretty well too.
This is my code with the main function:
#include <stdio.h>
#include <stdlib.h>
int is_separator(char c)
{
if (c == '\n' || c == '\t' || c == ' ' || c == '\0')
{
return (1);
}
else
{
return (0);
}
}
int ct_len(int index, char *str)
{
int i;
i = index;
while (!(is_separator(str[index])))
{
index++;
}
return (index - i);
}
int ct_wd(char *str)
{
int count;
int i;
i = 0;
count = 0;
while (str[i])
{
if (is_separator(str[i]))
count++;
i++;
}
return (count + 1);
}
char **ft_split_whitespaces(char *str)
{
char **tab;
int i;
int j;
int k;
i = 0;
j = 0;
tab = malloc(ct_wd(str));
while (str[j])
{
k = 1;
while (is_separator(str[j]))
j++;
*(tab + i) = (char *)malloc(sizeof(char) * ((ct_len(j, str) + 1)));
while (!(is_separator(str[j])))
{
tab[i][k - 1] = str[j++];
k++;
}
tab[i++][k - 1] = '\0';
}
tab[i] = 0;
return (&tab[0]);
}
int main(void)
{
char** res;
for (res = ft_split_whitespaces("asdf qwerty zxcv"); *res != 0; res++)
{
printf("'%s',", *res);
}
return (0);
}
One hint is that the output of the first array is changing, which suggests that there might be some problems with my memory allocation. However, I am not sure about it. If you can help me find out where the bug is, I would be really appreciative of your help. Thank you very much for reading.
this
tab = malloc(ct_wd(str));
to this
tab = malloc(ct_wd(str) * sizeof(char *));
also you wight want to consider using valgrind, which should provide a fair indication of where the corruption is. essentially ct_wd(str) function is the main culprit along with malloc statement after that. you might want to take a closer look at how much memory you are allocating and how much actually using. as mentioned valgrind should assist you better.
valgrind --tool=memcheck --leak-check=full --track-origins=yes <executalbe>

C programming: ouput two strings as two columns next to each other

I have a question regarding an issue with a program in C I am making. I am going to write two different strings next to each other in two columns. I haven't found clear answers to my question since they almost always give examples of numbers with a known length or amount.
I have two strings, with a maximum length of 1500 characters, but to me unknown length. Let's for the sake of learning given them these values:
char string1[] = "The independent country is not only self-governed nation with own authorities.";
char string2[] = "This status needs the international diplomatic recognition of sovereignty.";
I want to write them next to each other, with a column width of twenty characters. I have set the difference between the columns to a regular 'tab'. Like this:
The independent coun This status needs th
try is not only self e international dipl
-governed nation wit omatic recognition o
h own authorities. f sovereignty.
I have tried with the following code but it isn't effective since I can't figure out how to adapt it to the length of the strings. It also just adapted to write five rows. I also get the below error.
Could someone please give me an example of how this could be done, and maybe with a pre-defined c-function in order to avoid using the for-loops.
void display_columns(char *string1, char *string2);
int main()
{
char string1[] = "The independent country is not only self-governed nation with own authorities.";
char string2[] = "This status needs the international diplomatic recognition of sovereignty.";
display_columns(string1,string2);
}
void display_columns(char *string1, char *string2)
{
int i,j;
for(i=0;i<5;i++)
{
for(j=0+20*i;j<20+20*i;j++)
{
printf("%c",string1[j]);
}
printf("\t");
for(j=0+20*i;j<20+20*i;j++)
{
printf("%c",string2[j]);
}
}
}
I guess this is more generic way to do it.
void print_line(char *str, int *counter) {
for (int i = 0; i < 20; i++) {
if (str[*counter] != '\0') {
printf("%c", str[*counter]);
*counter += 1;
}
else { printf(" "); }
}
}
void display_columns(char *string1, char *string2)
{
int counter = 0, counter2 = 0;
while (1) {
print_line(string1, &counter);
printf("\t");
print_line(string2, &counter2);
printf("\n");
if (string1[counter] == '\0' && string2[counter2] == '\0') {
break;
}
}
}
To print a single character, use:
printf("%c",string1[j]);
or
putchar(string1[j]);
This is the reason for the warnings and segmentation fault.
With this fix, the program somewhat works, you just have to print a newline as the last part of the loop:
for(i=0;i<5;i++)
{
for(j=0+20*i;j<20+20*i;j++)
{
putchar(string1[j]);
}
printf("\t");
for(j=0+20*i;j<20+20*i;j++)
{
putchar(string2[j]);
}
putchar('\n');
}
Update: For the function to work with strings of variable lengths, try this:
void display_columns(char *string1, char *string2)
{
int i,j;
int len1 = strlen(string1);
int len2 = strlen(string2);
int maxlen = (len1 > len2) ? len1 : len2;
int numloops = (maxlen + 20 - 1) / 20;
for(i=0; i<numloops; i++)
{
for(j=0+20*i;j<20+20*i;j++)
{
if (j < len1)
putchar(string1[j]);
else
putchar(' '); // Fill with spaces for correct alignment
}
printf("\t");
for(j=0+20*i;j<20+20*i;j++)
{
if (j < len2)
putchar(string2[j]);
else
break; // Just exit from the loop for the right side
}
putchar('\n');
}
}

Resources