Longest relation between two strings - c

I am trying to find the maximum overlap between two strings without using any advanced functions or pointers but I am only able to find the overlap in the beginning of the strings using this code.
#include <stdio.h>
#include <string.h>
int main (void) {
char string1[256], string2[256];
int len = 0;
printf ("Enter string1");
fgets (string1, sizeof (string1), stdin);
printf ("Enter string2");
fgets (string2, sizeof (string2), stdin);
while (strncmp (string1, string2, len) == 0 && len < strlen (string1)) {
len = len + 1;
}
printf ("%d\n", len - 1);
printf (strcat (string1, string2));
return 0;
}
For example: If we enter "axyz" and "343axyz" it should get an output equal to 4. However, if I enter the similarity in the beginning "This is ax" and "This isas" is giving me the correct output 7.

You need two for/while loops to compute the maximum overlap.
In first loop, you step through the elements of the first string.
In the second loop, you step through the elements of the second string.
Keep track of the overall maximum overlap in a variable.
Compare the maximum overlap between the part of the first string and part of the second string as the inner function of the two loops.
Something like:
int maxOverlap = 0;
for (char* s1 = string1; *s1 != '\0'; ++s1)
{
for (char* s2 = string2; *s2 != '\0'; ++s2)
{
int overlap = 0;
while (s1[overlap] != '\0' && s1[overlap] == s2[overlap])
{
++overlap;
}
if ( maxOverlap < overlap )
{
maxOverlap = overlap;
}
}
}

Related

C program to remove consecutive repeated characters from string

The code: https://pastebin.com/nW6A49ck
/* C program to remove consecutive repeated characters from string. */
#include <stdio.h>
int main() {
char str[100];
int i, j, len, len1;
/* read string */
printf("Enter any string: ");
gets(str);
/* calculating length */
for (len = 0; str[len] != '\0'; len++);
/* assign 0 to len1 - length of removed characters */
len1 = 0;
/* Removing consecutive repeated characters from string */
for (i = 0; i < (len - len1);) {
if (str[i] == str[i + 1]) {
/* shift all characters */
for (j = i; j < (len - len1); j++)
str[j] = str[j + 1];
len1++;
} else {
i++;
}
}
printf("String after removing characters: %s\n", str);
return 0;
}
The problem: Lets say I have the string 'Hello' as an input..I want the two ls to be both removed (not only 1)... Same for 'Helllo' (I want the 3 ls to be removed and not just the 2 ls)... How can I do that?
if (str[i] == str[i + 1]) {
/* shift all characters */
for (j = i; j < (len - len1); j++)
str[j] = str[j + 1];
len1++;
}
Maybe I can count the times every character is repeated and then in line 28 replace 1 with the the times a character is repeated? But how can I implement this to the code?
You could make a function to remove the ranges with equal characters by copying character by character to a separate pointer in the string that you do not step forward if repeating characters are found:
void foo(char *str) {
for(char *wr = str; (*wr = *str) != '\0';) { // copy until `\0` is copied
++str; // step to the next character
if(*wr != *str) { // if the next char is not equal to `*wr`
++wr; // step `wr` forward to save the copied character
} else do {
++str; // `*wr == *str`, so step `str` forward...
} while(*wr == *str); // ...until a different character is found
}
}
*wr = *str copies the current character str is pointing at to where wr is currently poining. The != '\0' check makes the loop end when \0 (the null terminator) has been copied.
After that str is increased to point at the next character.
If the next character is not equal to the one which was just copied, increase wr to save that copied character.
If the next character was indeed equal to the one being copied, don't increase wr to let it be overritten by the next character being copied and step str forward until a different character is found.
Demo
A dense version doing exactly the same thing:
void foo(char *str) {
for(char *wr = str; (*wr = *str) != '\0';) {
if(*wr != *++str) ++wr;
else while(*wr == *++str);
}
}
This code snippet should remove all consecutive characters out of your string (note that some C compilers won't let you declare variables within the internal blocks):
for (int i=0; i<len; i++) {
int j = i, repeats = 1;
while (j < len-1 && str[j] == str[++j])
{
repeats++;
}
if (repeats > 1) {
for (j = i; j < len - repeats; j++)
{
str[j] = str[j + repeats];
}
len -= repeats;
i--;
str[len] = '\0';
}
}
Links are discouraged, instead, you should post the contents of link. Also, for such kind of problem, I will suggest first come up with an appropriate algorithm and then implement it. At time, you will find it much more easier than taking someone else's code and making changes to it make it work as per your need.
Algorithm:
Step I: Record the position where the letter to be written in the string (calling this position - P). Initially, it will be start of string.
Step II: If current processing character is same as it's next character, then
Dont make any change in P.
Set a flag to skip next character (calling this flag - F).
Step III: If current processing character and next character are different, then
If flag F is set, skip this character, reset flag F and don't change P.
If flag F is not set then write this character at position P in the string and set P to next position.
Step IV: Move to next character in the string and go to Step II.
Implementation:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
void remove_all_consecutive_dup_chars (char * pstr) {
if (pstr == NULL) {
printf ("Invalid input..\n");
return;
}
/* Pointer to keep track of position where next
* character to be write.
*/
char * p = pstr;
int skip_letter = 0;
for (unsigned int i = 0; pstr[i] ; ++i) {
/* Using tolower() to identify the consecutive characters
* which are same and only differ in case (upper/lower).
*/
if ((tolower (pstr[i]) == tolower (pstr[i + 1]))) {
skip_letter = 1;
continue;
}
if (skip_letter) {
skip_letter = 0;
} else {
*p++ = pstr[i];
}
}
/* Add the null terminating character.
*/
*p = '\0';
}
int main (void) {
char buf[256] = {'\0'};
strcpy (buf, "WELL, well, welLlLl....");
printf ("%s ----> ", buf);
remove_all_consecutive_dup_chars (buf);
printf ("%s\n", buf);
strcpy (buf, "Hello");
printf ("%s ----> ", buf);
remove_all_consecutive_dup_chars (buf);
printf ("%s\n", buf);
strcpy (buf, "Helllo");
printf ("%s ----> ", buf);
remove_all_consecutive_dup_chars (buf);
printf ("%s\n", buf);
strcpy (buf, "aAaaaA ZZz");
printf ("%s ----> ", buf);
remove_all_consecutive_dup_chars (buf);
printf ("%s\n", buf);
return 0;
}
Output:
# ./a.out
WELL, well, welLlLl.... ----> WE, we, we
Hello ----> Heo
Helllo ----> Heo
aAaaaA ZZz ---->
EDIT:
In above program, I have used tolower() with an assumption that the string, passed as argument to remove_all_consecutive_dup_chars(), will contain only alphabets - [A - Z]/[a - z] and space character.
Note that, tolower() can result in UB if pstr[i] < 0. If you use tolower(), just make sure that argument you pass to tolower() shall be representable as an unsigned char.

Reversing a string word by word

I'm trying to write a program that reverses a string inputted by the user.
Enter a sentence: you can cage a swallow can't you
Reversal of sentence: you can't swallow a cage can you
So I thought about scanning for the string character by character. Then copying the string from the end to the beginning into a new string. At this point, I know that I've got a new word every time I see a space, so I have to invert the order of the letters that are between two spaces. Here's my code:
#include <stdio.h>
#include <string.h>
int main(){
char sentence[64], reversal[64], reversal_copy[64];
int i = 0, index = 0;
printf("Enter a sentence: ");
while(sentence[strlen(sentence)-1]!= '\n'){
scanf("%c", &sentence[i]);
i++;
}
printf("Reversal of sencente: ");
for(int h = strlen(sentence) - 2, k = 0; h >= 0; h++, k++){
reversal[k] = sentence[h];
strcpy(reversal_copy, reversal);
if(sentence[h] == ' '){
for(int m = h; m >= index && m <= h; m--, index++){
reversal[m] = reversal_copy[index];
}
}
}
printf("Reversal of sentence: %s\n\n", reversal);
return 0;
}
I get a segmentation fault error and I believe it happens around here:
for(int h = strlen(sentence) - 2, k = 0; h >= 0; h++, k++){
reversal[k] = sentence[h];
but I don't quite get why. Could you help me with this?
The condition for your first loop to continue is h >= 0, and as you are incrementing h each time this is going to keep getting bigger until it exceeds the size of sentence and throws the error.
If your intention for that loop is to work backwards through sentence then I think you should decrement h and k (h--, k--), but if the intention is to work forwards through sentence then your condition needs to be changed so that the loop finishes once h has reached the end of sentence
The word order can be reversed using a recursive function.
#include <stdio.h>
#include <string.h>
void reverse ( char *str, char *original) {
char temp[strlen ( str) + 1];
temp[0] = 0;
int offset = 0;
if ( 1 == sscanf ( str, "%s%n", temp, &offset)) {
reverse ( str + offset, original);//recursive call
}
else {//at the end of the original string
*original = 0;//set zero at first character
return;
}
//as recursion unwinds, concatenate the words
strcat ( original, temp);
if ( str != original) {//will be false when unwinds reaches first iteration
strcat ( original, " ");
}
return;
}
int main( void) {
char text[] = "you can cage a swallow can't you";
printf ( "%s\n", text);
reverse ( text, text);
printf ( "%s\n", text);
return 0;
}
For starters:
During the while-loop's 1st iteration strlen() is called on an un-initialised variable. This invokes undefined behaviour. Anything can happen.
In any case of updating a char-array character by character you completely ignore the fact that a 0-terminator is necessary to make a char-array a C-string. Only a C-string may be passed to (most of the) str*() functions.
Also scanf() might fail. Test for this.

I don't know how to print a sentence only under certain circumstances

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.

C programming: strlcpy with len = 0 [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I'm just learning about programming using the C language.
Today, I'm trying to code my own strlcpy function and I am facing a problem.
To test my function I compare the results with the "official" function's ones. Everything works fine except... When I put 0 as the len arg.
The strcpy function seems to put a garbage character in the destination string and I really don't understand why.
Here is the function's prototype:
size_t strlcpy(char * restrict dst, const char * restrict src, size_t dstsize);
Thanks for your help!
Ok. I wanted to make a lot of tests, this is the reason why I'm calling the function inside of a loop.
Here is a part of my main function, testing the function:
do
{
/* Ask for first string */
printf("\nGive me a string (0 to stop): ");
gets(str);
/* Ask for a number */
printf("Now, give me a number please: ");
scanf("%d", &i);
while (getchar() != '\n');
/* I test with the "official function */
j = strlcpy(str2, str, i);
printf("Here is the expected result: %s\n", str2);
printf("Num returned: %d\n", j);
/* Now I test using my function */
j = ft_strlcpy(str3, str, i);
printf("Here is my result: %s\n", str3);
printf("Num returned: %d\n", j);
}while (str[0] != '0');
And here is the function I've coded:
unsigned int ft_strlcpy(char *dest, char *src, unsigned int size)
{
unsigned int cpt;
unsigned int i;
cpt = 0;
i = 0;
while (src[cpt] != '\0')
cpt++;
if (size == 0)
return (0);
while (i < cpt && i < (size - 1))
{
dest[i] = src[i];
i++;
}
dest[i] = '\0';
return (cpt);
}
In the function I'm not supposed to call any function from the standard library. My main is just here for testing.
The function prototype is given by my teacher, this is the reason why I don't respect the original one.
Sorry fort the time I needed to put my code here and thank you for your help.
could you explain me where the "garbage character" comes from? What does the function do to find this character and to put it in the string? Even if it is not supposed to be called with a 0 len value.
The manual does not say that strlcpy is not supposed to be called with a 0 len value, it only says that it isn't NUL-terminating the result if dstsize is 0, i. e. it copies no characters at all to dst.
Your impression that it would put a "garbage character" into the destination string most probably results from dst being uninitialized from the start, and you looking at the unchanged, uninitialized dst.
First of all, I suppose you mistype in "...strlen function seems to put a garbage..." (strlcpy should be instead of strlen, because strlen put nothing to string - size_t strlen(const char *s);).
So you have a question about strlcpy.
As referencess said about the third argument of strlcpy (as well as strncpy) determies number of characters to be copied from src to dst. So, in case of 0-size no data should be copied. Read documentation carefully - prototype is:
strlcpy(char *dst, const char *src, size_t size);
and explanation for size has words:
as long as size is larger than 0
There are several issues in your program.
First of all don't use gets(). It's not safe and moreover it has been obsoleted. Check this.
Instead use fgets(). Check this.
In this statement
printf("\nGive me a string (0 to stop): ");
0 to stop will actually not stop anything and execute all the statements below it until while loop checks the condition. May you want a put if condition, like this:
if (str[0] != '0') {
.....
.....
}
}while (str[0] != '0');
In this statement
printf("Now, give me a number please: ");
scanf("%d", &i);
....
....
j = ft_strlcpy(str3, str, i);
You are passing this number as the destination size to your ft_strlcpy() function. Assume your source string contains "123456789" string and destination string size is 5 and user has given number input as 100. In function ft_strlcpy(), for the given input
//cpt variable value would be 9
//size variable value would be 100
//initial value of i is 0
while (i < 9 && i < (100 - 1))
{
dest[i] = src[i]; //buffer overflow!!!!, this statement will execute 9 times and dest buffer size is 5
i++;
}
So, instead of taking the number of characters to be copy as input from user, you should give size of the destination buffer. Like this
j = ft_strlcpy(str3, str, sizeof(str3));
From strlcpy
strlcpy() copies up to dstsize - 1 characters from the string src to dst,
NUL-terminating the result if dstsize is not 0.
That means if destination buffer size is 0, no copy is performed.
Check this also.
Putting these all together, you can do:
#include <stdio.h>
#include <string.h>
unsigned int ft_strlcpy(char *dest, const char *src, unsigned int size) {
unsigned int i = 0, j = 0;
while (src[i] != '\0') {
if (size && (i < (size - 1))) {
dest[i] = src[i];
j++;
}
i++;
}
dest[j] = '\0';
return (i);
}
int main() {
char str[100], str3[100];
unsigned int j;
do {
/* Ask for first string */
printf("\nEnter a string (press only enter key to stop): ");
if (fgets(str, sizeof(str), stdin) == NULL) {
fprintf (stderr, "Failed to read input");
break;
}
/* If input is bigger than the size of buffer, discard the rest of input characters */
if (strchr(str, '\n') == NULL) {
int c;
while((c = getchar()) != '\n' && c != EOF)
/* discard the character */;
}
else {
/* Remove the trailing newline character */
str[strcspn(str, "\n")] = 0;
}
if (str[0] != '\0') {
j = ft_strlcpy(str3, str, sizeof(str3));
printf("Here is my result: %s\n", str3);
printf("Num returned: %d\n", j);
}
}while (str[0] != '\0');
return 0;
}

Trying to check if a number is a palindrome through the use of strings [duplicate]

This question already has answers here:
How do I check if a number is a palindrome?
(53 answers)
Closed 5 years ago.
I am trying to check if an input number is a palindrome. I am doing it through strings rather than ints. So, I am taking in a string and reversing it into another string. However, when I use the string compare function it does not give me 0, stating that the strings are not the same. Even when I put in for example "1001", both the input and reverse strings displays 1001. I have figured it out with other methods but am trying to understand what is wrong with this one in specific.
#include <stdio.h>
#include <string.h>
int main(void)
{
char input[100];
char reverse[100];
int numLen = 0;
printf("Enter a number\n");
fgets(input, 100, stdin);
printf("The number is: %s\n", input);
numLen = strlen(input) - 1;
printf("Length of string is: %d\n", numLen);
for (int i = 0; i < numLen; i++)
{
reverse[i] = input[numLen - 1 - i];
if (i == numLen - 1)
{
reverse[i + 1] = '\0';
}
}
printf("The reverse number is: %s\n", reverse);
printf("The original number is: %s\n", input);
int result = strcmp(input, reverse);
printf("Result of strcmp gives us: %d\n", result);
if (strcmp(input, reverse) == 0)
{
printf("These numbers are palindromes\n");
}
else
{
printf("These numbers are not palindromes\n");
}
return 0;
}
The problem is you are not handling the strings properly. You should overwrite the '\n' with \0.
...
char input[100];
char reverse[100];
int numLen = 0;
printf("Enter a number\n");
fgets(input, 100, stdin);
printf("The number is: %s\n", input);
input[strcspn(input,"\n")]='\0'; // getting the length of the
// string without `\n`
// and overwriting with `\0`
numLen = strlen(input) ; // now you don't need to put the -1
printf("Length of string is: %d\n", numLen);
for (int i = 0; i < numLen; i++)
{
....
Apart from these two changes everything else remains the same. You were reversing it all right. And then you used strcmp right way. But the extra \n is removed in the code I have shown.
(still) Why it works?
Now to give you a better idea. You formed the reversed string alright. But the original string has \n within itself.
printf("The reverse number is: (%s)\n", reverse);
printf("The original number is: (%s)\n", input);
In the previous program you just do write these two lines. You will understand where you went wrong.
On giving input 1001Enter it gives this output.
The reverse number is: (1001)
The original number is: (1001
)
What is strcspn doing?
I have using strcspn function got the length without \n and overwriting it with \0.
0 1 2 3 4 5 --> indices
1 0 0 1 \n \0 --> strcspn(input,"\n") returns 4.
1 0 0 1 \0 \0 --> input[strcspn(input,"\n")]='\0'
You can do simply like this without the copying and everything.
Without extra memory - in place palindrome checking
bool checkPal(const char *s){
for(int i = 0, j= strlen(s)-1; i< strlen(s) && j>=0 ; i++)
if(s[i] != s[j])
return false;
return true;
}
int main(void)
{
char input[100];
char reverse[100];
printf("Enter a number\n");
if( fgets(input, 100, stdin) )
printf("The number is: %s\n", input);
input[strcspn(input,"\n")]='\0';
int numLen = strlen(input) ;
printf("Length of string is: %d \n", numLen);
printf("These numbers are %spalindromes\n", checkPal(input)?"not ":"");
return 0;
}
A more succinct way to write the checkPal() would be,
bool checkPal(const char *first){
const char *last = first + strlen(first);
while (first < last) {
if (*first++ != *--last) {
return false;
}
}
return true;
}
last points to the \0 character. Subtraction is necessary before we start doing comparison. To get a clear idea of what happens you have to know the precedence and few rules.
The first<last part is obvious. We are comparing till we reach a point where we first > last (For even length strings) or first = last (for odd length strings).
The if is a bit tricky. *first++ there are two operators involved. * (indirection) and ++(post increment).
And precedence of ++ is higher than de-reference *.
So *first++ will be - first is incremented. Then you might think that we are missing one character very first time but that's not the case. Value of a postfix expression is the value before we do first++. So now you have the first character.
Same way *--last will have the same effect except the value of the prefix expression is the value after the operation. So you are considering the last character.
If they matches we continue. first and last already contain the modified value. We repeat the same logic for rest of the characters in the smaller sub-string.
If a mismatch occurs then we return immediately. (Because it's not a palindrome).
Sorry, my bad. Try this:
#include <stdio.h>
#include <string.h>
// A function to check if a string str is palindrome
void isPalindrome(char str[])
{
// Start from leftmost and rightmost corners of str
int l = 0;
int h = strlen(str) - 1;
// Keep comparing characters while they are same
while (h > l)
{
if (str[l++] != str[h--])
{
printf("%s is Not Palindromen", str);
return;
}
}
printf("%s is palindromen", str);
}
// Driver program to test above function
int main()
{
isPalindrome("abba");
isPalindrome("abbccbba");
isPalindrome("geeks");
return 0;
}
Does this one work?
A variant, recursive version that has no more that the string as argument (or a copy of the original string)
int pal(char *s) {
int n = strlen(s);
if (n <= 1) return 1;
if (s[0] != s[n-1]) return 0;
s[n-1] = '\0';
return pal(++s);
}
return 0: not a palindrome, 1: is a palindrome
Note the string is altered, so you can call it this way if it's a problem (or if the string is created in a static area)
char *copy = malloc(strlen(string)+1); // string is original string
strcpy(copy, string);
int ispal = pal( copy );
printf("Is %s a palindrome\n", ispal ? "":"not");

Resources