delete repetition in strings - c

i want to write code in c language to delete any character in string s1 which matches any character in the string s2 . using only for loops. that is my trial has failed -_- .
for example if s1="ahmed" and s2="omnia" should edit s1 to >> s1="hed"
#include <stdio.h>
#include <stdlib.h>
int i,j;
int k;
int counter=0;
int main()
{
char s1[100];
char s2[10];
char temp[100];
printf("\n enter string 1: ");
scanf("%s",s1);
printf("\n enter string 2: ");
scanf("%s",s2);
printf("\n%s",s1);
printf("\n%s",s2);
for(j=0;j<9;j++)
{
for(i=0;i<9;i++)
{
if(s1[i]!=s2[j]&&s1[i]!='\0')
{
temp[counter++]=s1[i]; //add unique items to temp
k=counter; //size
temp[counter]='\0';
}
}
}
for(i=0;i<k;i++)
{
s1[i]=temp[i];
}
printf("\nstring 1 after delete : ");
printf("%s",s1);
return 0;
}
how can i compare one item with nested items then achieve a condition ??

Why are you including the null character statements inside the if statement?
Try these two statements after the two for loops, like this. And please indent your code.
for(j=0;j<strlen(s1);j++) //Why is it 9 in your code? It should be the respective lengths
{
for(i=0;i<strlen(s2);i++)
{
if(s1[i]!=s2[j]&&s1[i]!='\0')
{
temp[counter++]=s1[i];
}
}
}
k=counter;
temp[counter]='\0';
and include:#include<string.h>

I don't see any coding errors here, only your logic is flawed.
This should work
for (j = 0; j < 9; j++)
{
for (i = 0; i < 9; i++)
{
if (s1[j] == s2[i] && s1[i] != '\0')
{
break;
}
else if (i == strlen(s2))
{
temp[counter++] = s1[j];
}
}
}
temp[counter] = '\0';
for (i = 0; i < counter; i++)
{
s1[i] = temp[i];
}
printf("\nstring 1 after delete : ");
printf("%s", s1);
In your original code you kept reading the original string from the beginning, instead of advancing the iterator each time.
So in the first iteration you compared 'ahmed' against 'omnia' which is fine.
In the second iteration though, you compared 'ahmed' against 'omnia', instead of 'hmed' against 'omnia', and that's why you got a large repetition of the original string in your output.
Also, I'd memset the memory of s1 and s2 first to 0.

Related

Array goes of out of bounds without giving any errors

My professor asked me to make a Codebreaker game in C. (User is breaking the code by guessing original code. original code is given as a cmd-line arg.After every attempt;(b, w): the number of correct colors in the correct positions (b) and the number of colors that are part of the code but not in the correct positions (w) are printed as Feedback.)Only standard input and output is allowed. I got it working, but the arrays Secret_Code2 and guess2 goes out of bounds. It has some strange behaviours like changing int variables causes changes in arrays even they are independent. I'm aware that C does not check array bounds, is there any improvements that i can make?
Here is my code;
#include <stdio.h>
#define Max_Attempts 12
char *Sectret_CODE = NULL;
int main(int argc,char **argv)
{
//Definitions
printf("Available Colors: (B)lue (G)reen (O)range (P)urple (R)ed (Y)ellow\n\n");
//Getting input and validating
if(argc != 2)
{
fprintf(stderr,"Invalid input\n");
return 1;
}
Sectret_CODE = argv[1];
int i = Max_Attempts;
int Won = 0;
while (i > 0 && !Won)
{
int b = 0, w = 0, t=0;
char guess[4];
char Sectret_CODE2[4];
char guess2[4];
printf("No. guesses left: %i\n",i);
printf("Enter Your Guess: ");
scanf("%s",guess);
//printf("%s",guess);
for(int j = 0; j < 4; j++)
{
//printf("%s,%s\n",Sectret_CODE2,guess2);
if(Sectret_CODE[j] == guess[j])
{
b++;
}
else
{
Sectret_CODE2[t] = Sectret_CODE[j];
guess2[t] = guess[j];
t++;
printf("%s,%s,%i\n",Sectret_CODE2,guess2,t);
}
}
int s = t;
//printf("%i",t);
Sectret_CODE2[t] = '\0' ;
guess2[t] = '\0' ;
if(b == 4)
{
printf("You Won\n");
Won = 1;
return 0;
}
else
{
for(int j = 0; j < s; j++)
{
for(int k = 0; k < s;k++)
if(Sectret_CODE2[j] == guess2[k])
{
w++;
break;
}
}
}
printf("Feedback: %i,%i\n",b,w);
i--;
}
if(!Won)
{
printf("You Lose!\n");
}
}
You aren't allocating space for the terminating null character in your character arrays. Each array needs to hold up to 4 values, plus a terminating null character. So you need to declare them to hold 4+1 = 5 characters. Otherwise writing the null character can write past the end of the arrays.
Also, inside your loop, you are attempting to print those arrays using printf with %s before null-terminating them. You need to null-terminate them, at the proper point, before printing them with %s.

Manipulating dynamically allocated 2D char arrays in C

I'm having trouble with trying to manipulate 2d dynamic arrays in C. What I want to do is to store a char string in every row of the the 2d array then perform a check to see if the string contains a certain character, if so remove all occurrences then shift over the empty positions. What's actually happening is I get an exit status 1.
More about the problem, for example if I have
Enter string 1: testing
Enter string 2: apple
Enter string 3: banana
I would want the output to become
What letter? a // ask what character to search for and remove all occurences
testing
pple
bnn
Here is my full code:
#include <stdio.h>
#include <stdlib.h>
void removeOccurences2(char** letters, int strs, int size, char letter){
// Get size of array
// Shift amount says how many of the letter that we have removed so far.
int shiftAmt = 0;
// Shift array says how much we should shift each element at the end
int shiftArray[strs][size];
// The first loop to remove letters and put things the shift amount in the array
int i,j;
for(i=0;i < strs; i++){
for(j = 0; j < size - 1; j++) {
if (letters[i][j] == '\0'){
break;
}
else {
// If the letter matches
if(letter == letters[i][j]){
// Set to null terminator
letters[i][j] = '\0';
// Increase Shift amount
shiftAmt++;
// Set shift amount for this position to be 0
shiftArray[i][j] = 0;
}else{
// Set the shift amount for this letter to be equal to the current shift amount
shiftArray[i][j] = shiftAmt;
}
}
}
}
// Loop back through and shift each index the required amount
for(i = 0; i < strs; i++){
for(j = 0; j < size - 1; j++) {
// If the shift amount for this index is 0 don't do anything
if(shiftArray[i][j] == 0) continue;
// Otherwise swap
letters[i][j - shiftArray[i][j]] = letters[i][j];
letters[i][j] = '\0';
}
//now print the new string
printf("%s", letters[i]);
}
return;
}
int main() {
int strs;
char** array2;
int size;
int cnt;
int c;
char letter;
printf("How many strings do you want to enter?\n");
scanf("%d", &strs);
printf("What is the max size of the strings?\n");
scanf("%d", &size);
array2 = malloc(sizeof(char*)*strs);
cnt = 0;
while (cnt < strs) {
c = 0;
printf("Enter string %d:\n", cnt + 1);
array2[cnt] = malloc(sizeof(char)*size);
scanf("%s", array2[cnt]);
cnt += 1;
}
printf("What letter?\n");
scanf(" %c", &letter);
removeOccurences2(array2,strs,size,letter);
}
Thanks in advance!
You can remove letters from a string in place, because you can only shorten the string.
The code could simply be:
void removeOccurences2(char** letters, int strs, int size, char letter){
int i,j,k;
// loop over the array of strings
for(i=0;i < strs; i++){
// loop per string
for(j = 0, k=0; j < size; j++) {
// stop on the first null character
if (letters[i][j] == '\0'){
letters[i][k] = 0;
break;
}
// If the letter does not match, keep the letter
if(letter != letters[i][j]){
letters[i][k++] = letters[i][j];
}
}
//now print the new string
printf("%s\n", letters[i]);
}
return;
}
But you should free all the allocated arrays before returning to environment, and explicitely return 0 at the end of main.
Well, there are several issues on your program, basically you are getting segmentation fault error because you are accessing invalid memory which isn't allocated by your program. Here are some issues I found:
shiftAmt isn't reset after processing/checking each string which lead to incorrect value of shiftArray.
Values of shiftArray only set as expected for length of string but after that (values from from length of each string to size) are random numbers.
The logic to delete occurrence character is incorrect - you need to shift the whole string after the occurrence character to the left not just manipulating a single character like what you are doing.
1 & 2 cause the segmentation fault error (crash the program) because it causes this line letters[i][j - shiftArray[i][j]] = letters[i][j]; access to unexpected memory. You can take a look at my edited version of your removeOccurences2 method for reference:
int removeOccurences2(char* string, char letter) {
if(!string) return -1;
int i = 0;
while (*(string+i) != '\0') {
if (*(string+i) == letter) {
memmove(string + i, string + i + 1, strlen(string + i + 1));
string[strlen(string) - 1] = '\0'; // delete last character
}
i++;
}
return 0;
}
It's just an example and there is still some flaw in its logics waiting for you to complete. Hint: try the case: "bananaaaa123"
Happy coding!
"...if the string contains a certain character, if so remove all occurrences then shift over the empty positions."
The original string can be edited in place by incrementing two pointers initially containing the same content. The following illustrates.:
void remove_all_chars(char* str, char c)
{
char *pr = str://pointer read
char *pw = str;//pointer write
while(*pr)
{
*pw = *pr++;
pw += (*pw != c);//increment pw only if current position == c
}
*pw = '\0';//terminate to mark last position of modified string
}
This is the cleanest, simplest form I have seen for doing this task. Credit goes to this answer.

A program that prints even and odd characters from a string

This is for Homework
I have to write a program that asks the user to enter a string, then my program would separate the even and odd values from the entered string. Here is my program.
#include <stdio.h>
#include <string.h>
int main(void) {
char *str[41];
char odd[21];
char even[21];
int i = 0;
int j = 0;
int k = 0;
printf("Enter a string (40 characters maximum): ");
scanf("%s", &str);
while (&str[i] < 41) {
if (i % 2 == 0) {
odd[j++] = *str[i];
} else {
even[k++] = *str[i];
}
i++;
}
printf("The even string is:%s\n ", even);
printf("The odd string is:%s\n ", odd);
return 0;
}
When I try and compile my program I get two warnings:
For my scanf I get "format '%s' expects arguments of type char but argument has 'char * (*)[41]". I'm not sure what this means but I assume it's because of the array initialization.
On the while loop it gives me the warning that says comparison between pointer and integer. I'm not sure what that means either and I thought it was legal in C to make that comparison.
When I compile the program, I get random characters for both the even and odd string.
Any help would be appreciated!
this declaration is wrong:
char *str[41];
you're declaring 41 uninitialized strings. You want:
char str[41];
then, scanf("%40s" , str);, no & and limit the input size (safety)
then the loop (where your while (str[i]<41) is wrong, it probably ends at once since letters start at 65 (ascii code for "A"). You wanted to test i against 41 but test str[i] against \0 instead, else you get all the garbage after nul-termination char in one of odd or even strings if the string is not exactly 40 bytes long)
while (str[i]) {
if (i % 2 == 0) {
odd[j++] = str[i];
} else {
even[k++] = str[i];
}
i++;
}
if you want to use a pointer (assignement requirement), just define str as before:
char str[41];
scan the input value on it as indicated above, then point on it:
char *p = str;
And now that you defined a pointer on a buffer, if you're required to use deference instead of index access you can do:
while (*p) { // test end of string termination
if (i % 2 == 0) { // if ((p-str) % 2 == 0) { would allow to get rid of i
odd[j++] = *p;
} else {
even[k++] = *p;
}
p++;
i++;
}
(we have to increase i for the even/odd test, or we would have to test p-str evenness)
aaaand last classical mistake (thanks to last-minute comments), even & odd aren't null terminated so the risk of getting garbage at the end when printing them, you need:
even[k] = odd[j] = '\0';
(as another answer states, check the concept of even & odd, the expected result may be the other way round)
There are multiple problems in your code:
You define an array of pointers char *str[41], not an array of char.
You should pass the array to scanf instead of its address: When passed to a function, an array decays into a pointer to its first element.
You should limit the number of characters read by scanf.
You should iterate until the end of the string, not on all elements of the array, especially with (&str[i] < 41) that compares the address of the ith element with the value 41, which is meaningless. The end of the string is the null terminator which can be tested with (str[i] != '\0').
You should read the characters from str with str[i].
You should null terminate the even and odd arrays.
Here is a modified version:
#include <stdio.h>
int main(void) {
char str[41];
char odd[21];
char even[21];
int i = 0;
int j = 0;
int k = 0;
printf("Enter a string (40 characters maximum): ");
if (scanf("%40s", str) != 1)
return 1;
while (str[i] != '\0') {
if (i % 2 == 0) {
odd[j++] = str[i];
} else {
even[k++] = str[i];
}
i++;
}
odd[j] = even[k] = '\0';
printf("The even string is: %s\n", even);
printf("The odd string is: %s\n", odd);
return 0;
}
Note that your interpretation of even and odd characters assumes 1-based offsets, ie: the first character is an odd character. This is not consistent with the C approach where an even characters would be interpreted as having en even offset from the beginning of the string, starting at 0.
Many answers all ready point out the original code`s problems.
Below are some ideas to reduce memory usage as the 2 arrays odd[], even[] are not needed.
As the "even" characters are seen, print them out.
As the "odd" characters are seen, move them to the first part of the array.
Alternative print: If code used "%.*s", the array does not need a null character termination.
#include <stdio.h>
#include <string.h>
int main(void) {
char str[41];
printf("Enter a string (40 characters maximum): ");
fflush(stdout);
if (scanf("%40s", str) == 1) {
int i;
printf("The even string is:");
for (i = 0; str[i]; i++) {
if (i % 2 == 0) {
str[i / 2] = str[i]; // copy character to an earlier part of `str[]`
} else {
putchar(str[i]);
}
}
printf("\n");
printf("The odd string is:%.*s\n ", (i + 1) / 2, str);
}
return 0;
}
or simply
printf("The even string is:");
for (int i = 0; str[i]; i++) {
if (i % 2 != 0) {
putchar(str[i]);
}
}
printf("\n");
printf("The odd string is:");
for (int i = 0; str[i]; i++) {
if (i % 2 == 0) {
putchar(str[i]);
}
}
printf("\n");
here is your solution :)
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[41];
char odd[21];
char even[21];
int i = 0;
int j = 0;
int k = 0;
printf("Enter a string (40 characters maximum): ");
scanf("%s" , str);
while (i < strlen(str))
{
if (i % 2 == 0) {
odd[j++] = str[i];
} else {
even[k++] = str[i];
}
i++;
}
odd[j] = '\0';
even[k] = '\0';
printf("The even string is:%s\n " , even);
printf("The odd string is:%s\n " , odd);
return 0;
}
solved the mistake in the declaration, the scanning string value, condition of the while loop and assignment of element of array. :)

A program to remove common alphabets from character array

void main()
{
int i, j, k,flag=1;
char key[10], keyword[10];
gets(key);
i=0;
j=0;
while(key[i]!='\0') {
k=0;
while(keyword[k]!='\0') {
if(key[i]==keyword[k]) {
i++;
flag=0;
break;
}
k++;
}
if(flag==1) {
keyword[j]=key[i];
j++;
i++;
}
flag=1;
}
}
Here I tried to copy unique alphabets from array to another array ..means duplicate alphabet should not copied in another array..it shows right output but along with that it shows some garbage values like smiley or something till the length of original input array(i.e.key[])
You need to add a terminator to the unique character string both at the time it is initialized, and every time a new letter is added:
#include <stdio.h>
int main() {
int i = 0, j = 0;
char redundant[10], unique[10] = { '\0' };
gets(redundant);
while (redundant[i] != '\0') {
int k = 0, flag = 1;
while (unique[k] != '\0') {
if (redundant[i] == unique[k]) {
flag = 0;
break;
}
k++;
}
if (flag) {
unique[j++] = redundant[i];
unique[j] = '\0';
}
i++;
}
printf("%s -> %s\n", redundant, unique);
return(0);
}
OUTPUT
% ./a.out
warning: this program uses gets(), which is unsafe.
aardvark
aardvark -> ardvk
%
Now let's consider a different approach that wastes some space to simplify and speed up the code:
#include <stdio.h>
#include <string.h>
int main() {
unsigned char seen[1 << (sizeof(char) * 8)] = { 0 }; // a flag for every ASCII character
char redundant[32], unique[32];
(void) fgets(redundant, sizeof(redundant), stdin); // gets() is unsafe
redundant[strlen(redundant) - 1] = '\0'; // toss trailing newline due to fgets()
int k = 0; // unique character counter
for (int i = 0; redundant[i] != '\0'; i++) {
if (!seen[(size_t) redundant[i]]) {
unique[k++] = redundant[i];
seen[(size_t) redundant[i]] = 1; // mark this character as seen
}
}
unique[k] = '\0'; // terminate the new unique string properly
printf("%s -> %s\n", redundant, unique);
return 0;
}
Instead of a second, inner loop to search if a letter has been copied already, we use an array of flags (boolean), where the letter is the index, to determine if the letter has been processed.
Another thing you might want to think about is whether to treat upper and lower case differently or fold them into one.

Strings (C) - Comparing letters of two strings

Trying to write that function checks whether all the letters in word appear in s, in the same order. If a letter appears several times in word, then it should appear
at least as many times in s.
For example:
containsLetters2("abcdef", "aaabbb")
returns 0 because there are no three appearances of the letter "a" followed by three appearances of the letter “b”.
This:
containsLetters2("axaxxabxxbxbcdef","aaabbb")
returns 1
I can't understand whats wrong in my code:
int containsLetters2(char *s, char *word)
{
int j,i, flag;
long len_word, len_s;
len_s=strlen(s);
len_word=strlen(word);
for (i=0; i<=len_word; i++) {
flag=0;
for (j=0; j<=len_s; j++) {
if (*word==*s) {
flag=1;
word++;
break;
}
s++;
}
if (flag==0) {
break;
}
}
return flag;
}
int main() {
char string3[MAX_STRING] , string4[MAX_STRING];
printf("Enter 2 strings for containsLetters2\n");
scanf ("%s %s", string3, string4);
printf("Return value from containsLetters2 is: %d\n",containsLetters2(string3,string4));
return 0; }
for (i=0; i<=len_word; i++) {
flag=0;
for (j=0; j<=len_s; j++) {
if (*word==*s) {
You have two obvious problems. One is an off by one error. If the length is 10, then your code processes elements from 0 to 10, which is 11 elements, not 10. Second, you keep comparing *word to *s. What you want is word[i] compared to s[j].
There are lots more problems that are not as obvious. I'd strongly suggest you take a step back and start by documenting the algorithm your code is supposed to follow. That will make it easier to debug the code as you will know precisely what it is supposed to be doing.
The following code may not compile, but will do what you want it to do, hope it helps:
int containsLetters2(char *s, char *word) {
int lastIndex = 0;
for (int i = 0; i < strlen(word); i++) {
for (; lastIndex < strlen(s) && s[lastIndex] != word[i]; lastIndex++);
if (lastIndex == strlen(s)) {
return 0;
}
}
return 1;
}
You should preserve the value of variable j,
For example,
word = "aaabbb"
s = "axaxxabxxbxbcdef"
The 1st iteration, word[1] == s[1], then it break and come to the 2nd iteration,
at this time, j is reset to zero, and word[2] == s[1].
This got to be wrong.
Change your code as below to see if it helps,
i=j=0;
for (; i<len_word; i++) {
flag=0;
for (; j<len_s; j++) {
if (*word==*s) {
flag=1;
word++;
break;
}
s++;
}
if (flag==0) {
break;
}
}

Resources