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.
Related
The output of my code is incorrect. For example, if I input "joy is joyful", then want to remove the word "joy", the output should be " is joyful", but instead the output is the same as the input.
Here is the full code:
#include<stdio.h>
#include<conio.h>
#include<string.h>
void print(char string[100]);
main()
{
char string[100], remove[100];
int stringLen, removeLen, i, j, k, l, count, location, sLen, ij, counter = 0;
printf("Enter any string: ");
gets(string);
printf("Enter word to remove: ");
gets(remove);
printf("\nString before removing '%s': ", remove);
print(string);
stringLen = strlen(string);
sLen = stringLen;
removeLen = strlen(remove);
for(i=0; i<stringLen; i++)
{
count = 0;
for(j=0; j<removeLen; j++)
{
if(string[i+j] == remove[j])
{
count++;
location = i;
ij = i+j;
}
}
if(count == removeLen)
{
if(string[ij+1] == '\0' && string[ij+1] == ' ' && string[ij+1] == '\n')
{
counter = count;
}
else
{
counter = count - 1;
}
}
if(counter == removeLen)
{
for(l=0; l<count; l++)
{
for(k=location; k<sLen; k++)
{
string[k] = string[k+1];
}
sLen--;
}
}
}
printf("\n\nString after removing '%s':", remove);
print(string);
getch();
return 0;
}
void print(char string[100])
{
printf("\n%s", string);
}
I tried making this part:
if(count == removeLen)
{
if(string[ij+1] == '\0' && string[ij+1] == ' ' && string[ij+1] == '\n')
{
counter = count;
}
else
{
counter = count - 1;
}
}
To this and it worked:
if(count == removeLen)
{
if(string[ij+1] != '\0' && string[ij+1] != ' ' && string[ij+1] != '\n')
{
counter = count - 1;
}
else
{
counter = count;
}
}
What seems to be the problem with the original one?
For pf all, never, ever, EVER, use gets(). It is so prone to exploit by buffer overrun that is have been removed from the C-library beginning with C11. For more discussion see: Why gets() is so dangerous it should never be used!
In your word replacement, you are not worrying about removing leading or trailing whitespace before or after the word you remove and you only remove that word if it is not a substring in a larger word or a word followed by punctuation. (this is fine -- but in isolating an removing words you will generally want to takes what is left into consideration)
You can simplify what you are attempting to do and reduce the complete algorithm to a single loop over the character in the string. You simply keep three indexes (or counters if you want to think of it that way). You need a read-index, the next character to be read. You need a write-index, the next location in the string to be written. And finally you need a remove-index to the characters in the substring to be removed.
Here you simply loop over the characters in the string with your read-index. Your read and write indexes begin the same. If a letter matches the first letter in your remove substring, you increment your remove-index and loop again. If a sequence of characters match all characters in your remove substring, on the next iteration your substring index will be at its nul-terminating character.
Now you can test if the next character under the read-index in your string is a space (using the isspace() macro) or testing if you are at the end of your original string. If either case is true, you simply subtract the substring length from your write-index and continue on -- effectively removing the substring from your original string. There are no multiple-loops needed, you are essentially working through each character of the original keep track of where you are (the state) with the substring index.
A short example approaching it this way could be something like the following. The function remove_substr(), reads the characters in str and removes each isolated occurrence of substr within it updating the original str in-place:
int remove_substr (char *str, const char *substr)
{
if (!strstr (str, substr)) /* if substr not found in str */
return 0; /* return 0 - nothing replaced */
size_t sslen = strlen (substr), /* length of substr */
i = 0, j = 0, n = 0; /* read, write, substr indexes */
do { /* loop over str (including '\0') */
if (!substr[n]) { /* substr found (at substr '\0') */
/* if at end of str or whitespace */
if (!str[i] || isspace((unsigned char)str[i]))
j -= sslen; /* subtract sslen from write index */
n = 0; /* reset substr index */
}
str[j++] = str[i]; /* copy from read to write index */
if (str[i] == substr[n]) /* if char matches substr */
n++; /* increment substr counter */
} while (str[i++]); /* exit after '\0' processed */
return 1; /* return replacements made */
}
A simple type int was chosen for the return type to indicate 0 no removals took place, or 1 indicating that occurrences of substr were removed from str.
A short example calling the function could be:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAXC 1024
/* insert function here */
int main (void) {
char str[MAXC] = "", /* storage for string */
substr[MAXC] = ""; /* storage for substring */
fputs ("enter string: ", stdout); /* prompt for string */
if (!fgets (str, sizeof str, stdin)) /* read/validate input */
return 1;
str[strcspn(str, "\n")] = 0; /* overwrite '\n' with '\0' */
fputs ("enter substr: ", stdout); /* ditto for substr */
if (!fgets (substr, sizeof substr, stdin))
return 1;
substr[strcspn(substr, "\n")] = 0;
if (remove_substr (str, substr)) /* remove all substr in str */
printf ("\nresult: '%s'\n", str); /* output updated str if removals */
else
puts ("\nno replacements made"); /* otherwise output no replacements */
}
Simply run the program and you will be prompted to input the string and the substring to remove. Currently each of the strings used are limited to MAXC (1024 characters), adjust to meet your needs -- but don't skimp on buffer size.
Example Use/Output
$ ./bin/str_rm_substr
enter string: joy is joyful
enter substr: joy
result: ' is joyful'
A more complicated example:
$ ./bin/str_rm_substr
enter string: joy is joyful, joy is full of joy
enter substr: joy
result: ' is joyful, is full of '
There are many ways to write a function like this. You can use combinations of strtok() to tokenize a copy of your original string checking whether each token matches your substr to remove. You can inch-worm down your string using multiple loops to scan forward to find the first letter in your substr and then loop to see if it matches. You can also use combinations of strspn() and strcspn() to do the same inch-worm technique, letting those function handle looping for you. There are probably a 1/2-dozen or so valid approaches.
Look things over and let me know if you have questions.
Here
if(string[ij+1] == '\0' && string[ij+1] == ' '
you test if a character is both a nul and a space.
That will never be true. In order words, the whole if-statement is useless as it always takes the false path.
The problem is in this case if(string[ij+1] == '\0' && string[ij+1] == ' ' && string[ij+1] == '\n') and the counter decreasing. So after decreasing you never will get into this code:
if(counter == removeLen)
{
for(l=0; l<count; l++)
{
for(k=location; k<sLen; k++)
{
string[k] = string[k+1];
}
sLen--;
}
}
So remove this code:
if(count == removeLen)
{
if(string[ij+1] == '\0' && string[ij+1] == ' ' && string[ij+1] == '\n')
{
counter = count;
}
else
{
counter = count - 1;
}
}
And it will be work.
I did this program to reverse the order of the words in the give string. (And it works)
i.e. Output: sentence first the is This
However I am stuck when it comes to adding another sentence to the array.
For example I need to have an array {"This is the first sentence", "And this is the second"} producing as output: sentence first the is This , second the is this And
int main() {
char str[] = {"This is the first sentence"};
int length = strlen(str);
// Traverse string from end
int i;
for (i = length - 1; i >= 0; i--) {
if (str[i] == ' ') {
// putting the NULL character at the position of space characters for
next iteration.
str[i] = '\0';
// Start from next character
printf("%s ", &(str[i]) + 1);
}
}
// printing the last word
printf("%s", str);
return 0;
}
I am new to C so its not surprising that I got stuck even if the solution is quite easy. Any help would be appreciated! Thanks!
Since you already have the code to print the words of one string in reverse order, I would suggest making that a function which takes a single string as an argument, i.e.:
void print_words_reverse(char * const str) {
// your current code here
}
Then you can call it separately for each string:
char strings[][30] = {
"This is the first sentence",
"And this is the second"
};
for (int i = 0; i < sizeof(strings) / sizeof(*strings); ++i) {
print_words_reverse(strings[i]);
}
Note that since you are modifying the string (by replacing spaces with NUL bytes), the argument needs to be modifiable, which means you are not allowed to call it (in standard C) with a pointer to a string literal, which means you can't simply use const char *strings[] = { "first", "second" }. You could get rid of the ugly constant length (here 30) reserved for every string by making your code not modify the argument string. Or you could have a separate char array for each sentence and then use pointers to those (modifiable) strings.
First, you can try with a two-dimensional array or use an array of pointers.
Secondly, in your approach, you lose the initial value of your string, I don't know how important it is.
This is my fast approach using arrray of pointers.
#include <stdio.h>
#include <string.h>
static void print_word(const char *str)
{
for (int i = 0; str[i] && str[i] != ' '; i++)
printf("%c", str[i]);
putchar(' ');
}
int main(void)
{
int len;
const char *str[] = {"This is the first sentence",
"And this is second", NULL};
for (int i = 0; str[i]; i++) {
for (len = strlen(str[i]); len >= 0; len--) {
if (len == 0)
print_word(&str[i][len]);
else if (str[i][len] == ' ')
print_word(&str[i][len + 1]);
}
putchar('\n');
}
printf("Initial value of array of strings [%s | %s] \n", str[0], str[1]);
return 0;
}
output is:
sentence first the is This
second is this And
Initial value of array of strings [This is the first sentence | And this is second]
I suggest you using memcpy but without altering too much your code this seems to work
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_STRING_LENGTH 100
int main()
{
char *str[] = {"This is the first", "And this is the second sentence"};
const size_t NUM_STRING = sizeof(str)/sizeof(char*);
/*%z used to print size_t variables*/
printf("%zd strings found\n", NUM_STRING);
int length[2];
int i;
for (i=0; i<NUM_STRING; i++)
{
length[i] = strlen(str[i]);
}
printf("length initialized %d %d\n", length[0], length[1]);
// Traverse string from end
int j = 0;
char temp[MAX_STRING_LENGTH];
printf("\n\n");
for (j=0; j<NUM_STRING; j++)
{
/*Make sure the string respect the MAX_STRING_LENGTH limit*/
if (strlen(str[j])>MAX_STRING_LENGTH)
{
printf("ERROR: string %d exceding max string length %d defined in constant "
"MAX_STRING_LENGTH. Exiting from program.\n", j, MAX_STRING_LENGTH);
exit(1);
}
//reset temporary string
memset(temp, '\0', sizeof(temp));
//printf("temp variable reinitialized\n");
for (i = length[j] - 1; i >= 0; i--)
{
temp[i] = str[j][i];
if (str[j][i] == ' ')
{
// putting the NULL character at the position of space characters for next iteration.
temp[i] = '\0';
// Start from next character
printf("%s ", &(temp[i]) + 1);
}
}
// printing the last word
printf("%s ", temp);
}
printf("\n");
return 0;
}
I do this program which receives input from a string and a substring, and then searches for the substring within the string by determining how often it appears (the number of occurrences) and the locations it is located, then these positions are inserted into an array for example (4 5 8) And they are printed correctly, now what I was trying to do, once I got my array with inside the locations where the substring was found it print it in reverse ie (8 5 4) I tried using this cycle
// reverse output
printf ("%d", count);
for (j = count - 1; j >= 0; j--)
printf("%d", pos[j]);
But if the array positions are 8 5 4 so it prints to me
5 ,4, -311228772
Why does this happen? Here is the code:
// inclusion of libraries
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
Reads a string allocated by the stream.
It stops at newline, not included in string.
Returns NULL to EOF
*/
char *my_getline(FILE *stream) { // statement of function
char *line = NULL; // this is just the pointer initialization
size_t pos = 0; // definition of position variables and init
int c; // a variable to store the temporary character
while ((c = getc(stream)) != EOF) // read every character until the end of the file
{
char *newp = realloc(line, pos + 2); // To dynamically allocate memory, with reference to the number of characters and more '2' is only to compensate for the null character and the character (since it is 0)
if (newp == NULL) { // checks whether memory has been properly associated or not.
free(line); // if the line is not free the blank
return NULL; // interrupts the program and returns NULL
}
line = newp; // if memory is allocated correctly stores the memory allocated to the line pointer
if (c == '\n') // if a new line is detected
break; // interrupts the while cycle
line[pos++] = (char)c; // stores the character in dynamic memory and the new character in the new location.
}
if (line) { // if the line contains something then a null character is added at the end to complete that string.
line[pos] = '\0';
}
return line; // returns the contents of the line.
}
int main(void) { // main statement
char *str, *sub; // character punctuation statement
size_t len1, len2, i, count = 0; // unsigned value statement "size_t is equal to unsigned int" so may also be <0
int pos[count]; // declare a count array to insert the index then print it in reverse
int j;
// Here is the main string
printf("Enter Main String: \n"); // print the entry and enter the main string
str = my_getline(stdin); // inserts the entered string inside the pointer using my_getline function and using getchar analogue stdin to make the entered characters input from the standard input
// here is the substring to look for
printf("Enter substring to search: \ n"); // print the entry and enter the main substring
sub = my_getline(stdin); // inserts the entered string inside the pointer using my_getline function and using getchar analogue stdin to make the entered characters input from the standard input
if (str && sub) { // if string and substring && = and
len1 = strlen(str); // inserts the string length in the len1 variable
len2 = strlen(sub); // inserts the length of the string in the len2 variable
for (i = 0; i + len2 <= len1; i++) { // loop for with the control that the substring is less than or equal to the main string ie len2 <= len1
if (! memcmp(str + i, sub, len2)) { // here uses the memcmp function to compare the string and substring byte bytes
count++; // count variable that is incremented each time the sub is found in p
// here is where it gets in output
// If the substring was found mold the index with the locations it was found
pos[count] = i + 1;
printf( "%d\n", pos[count]);
}
}
// print to get reverse output
printf("number of times%d", count);
// print to get reverse output
printf("%d", count);
for (j = count - 1; j >= 0; j--)
printf("%d", pos[j]);
if (count == 0) { // if count is = 0 ie the substring was not found string string not found
// otherwise if not found
printf("Subtry not found \n");
}
}
// free releases the memory area that was reserved for the string and substrings so that it can be reused in the next run
free(str);
free(sub);
return 0; // exit analog
}
Your code is completely unreadable. Even reformatted and spaced out, the comments make it difficult to see the important stuff.
You should only comment the non obvious: int main(void) {// main statement is a good example of a useless counter productive comment.
After removing all comments, the code shows a few problems:
There is an extra space in printf("Enter substring to search: \ n");
The array pos is defined with a size of 0: int count = 0; int pos[count];. The program has undefined behavior.
count is incremented before storing the offset into the array. Hence the array contents does not start at index 0, hence producing incorrect output when you iterate from count-1 down to 0 in the second loop.
Here is a simplified and corrected version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
Reads a string from the stream allocated with malloc
stops at newline, not included in string.
Returns NULL at EOF
*/
char *my_getline(FILE *stream) {
char *line = NULL;
size_t pos = 0;
int c;
while ((c = getc(stream)) != EOF) {
char *newp = realloc(line, pos + 2);
if (newp == NULL) {
free(line);
return NULL;
}
line = newp;
if (c == '\n')
break;
line[pos++] = (char)c;
}
if (line) {
line[pos] = '\0';
}
return line;
}
int main(void) {
printf("Enter Main String:\n");
char *str = my_getline(stdin);
printf("Enter substring to search:\n");
char *sub = my_getline(stdin);
if (str && sub) {
size_t count = 0;
size_t len1 = strlen(str);
size_t len2 = strlen(sub);
size_t pos[len1 + 1];
for (size_t i = 0; i + len2 <= len1; i++) {
if (!memcmp(str + i, sub, len2)) {
pos[count] = i + 1;
printf("%d\n", (int)pos[count]);
count++;
}
}
if (count != 0) {
printf("number of times: %d\n", (int)count);
for (size_t j = count; j-- > 0;) {
printf(" %d", (int)pos[j]);
}
printf("\n");
} else {
printf("substring not found.\n");
}
}
free(str);
free(sub);
return 0;
}
You declared pos as an array of length 0:
size_t ... count = 0;
int pos [count];
Thus, inside your for-loop you'll access some unitialized memory:
for (j = count-1; j>= 0; j--)
printf ("%d", pos [j]);
So I'm given a string as such:
Hello6World66ABC
Where I'm told to replace single instances of the character '6' to be two asteric characters "**"
And multiple instances of 6's to be two of these characters "^^" (Any combinations of the number 6 in a row would qualify.
I'm attempting to do this by passing through each character in a char *,then if I find the 6 character, I check if the next character is a 6, if not we have the first case, otherwise we have the second case (Multiple 6's).
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void) {
char * str;
int i;
str = malloc(17);
strcpy(str,"Hello6World66ABC");
for(i=0; i < strlen(str); i++) {
if(str[i] == '6') {
if(str[i+1] != '6') {
char * token = strtok(str,"6");
strcpy(str,token);
strcat(str,"**");
printf("String is now %s\n",str);
token = strtok(NULL,""); /*get the rest of the string*/ /* should be World66ABC */
printf("Rest of the string is %s\n",token);
str = (char *) realloc(str,strlen(str) + strlen(token) + 1);
strcat(str,token);
printf("String is now %s\n",str);
/* should be Hello**World66ABC */
}
else {
/*if the next characters are also (multiple ones in a row) 6's, replace it with two ^^ characters*/
char * token = strtok(str,"6");
token = strtok(NULL,"6");
printf("TOKEN IS %s\n",token);
strcpy(str,token);
strcat(str,"^^");
token = strtok(NULL,""); /*get the rest of the string*/ /* should be World66ABC */
printf("Rest of the string is %s\n",token);
str = (char *) realloc(str,strlen(str) + strlen(token) + 1);
strcat(str,token);
printf("String is now %s\n",str);
}
}
}
free(str);
return 0;
}
By the string given, My expected final string should be:
Hello**World^^ABC
However, my strtok calls don't work the way I intended.
In the second if statement, where I check if (str[i+1] != '6'), I'm checking if there is only a single 6, there is.
Then I call strtok and print everything before it:
it prints: Hello**
Which is correct
I strcat the new characters on to it which works, however, on my second strtok call, to get the rest of the string, it just doesn't work.
It instead prints:
"Rest of the string is *"
So clearly it's not getting the rest of the string, even though I set the delimiter to be an empty string.
I tried to change the delimiter to be other characters, but each result in the same output. I'm also reallocating because the string gets longer, in the first case. Also the else statement seems to never run, even though I clearly have a case where there are multiple 6's.
I'm not sure where I've gone wrong here, any ideas?
This is untested, but it shows the general idea.
strcpy(str,"Hello6World66ABC");
// New string will be at most 2x as long
char *new_str = calloc(strlen(str) * 2 + 1, 1);
int new_str_index = 0;
for (int i = 0; 0 != str[i]; i++) {
// Check for 6
if ('6' == str[i]) {
// Check for 2nd 6
if ('6' == str[i+1]) {
// Add chars
new_str[new_str_index++] = '^';
new_str[new_str_index++] = '^';
// Consume remaining 6s - double check this for off-by-one
while ('6' == str[i+1]) i += 1;
}
else {
// Add chars
new_str[new_str_index++] = '*';
new_str[new_str_index++] = '*';
}
}
// No 6s, just append text
else {
new_str[new_str_index++] = str[i];
}
}
OP asked for a simple way of altering the '6' characters in the string. If you want to write to another string instead of printing directly, I leave it to you to define the other (large enough) string, and copy the chars to that string instead of to stdout. But do NOT try to alter the string passed, it is doomed to fail.
#include <stdio.h>
void sixer(char *str)
{
int i = 0, sixes;
while(str[i] != '\0') {
if(str[i] == '6') {
sixes = 0;
while(str[i] == '6') {
sixes++;
i++;
}
if(sixes == 1) {
printf("**");
}
else {
printf("^^");
}
}
else {
printf("%c", str[i]);
i++;
}
}
printf("\n");
}
int main(void)
{
sixer("Hello6World66ABC");
sixer("6");
sixer("66666");
return 0;
}
Program output
Hello**World^^ABC
**
^^
I have to change the 2nd letter with penultimate letter for word with more than 3 letters.
Example i have this string: Alex are mere
The result should be: Aelx are mree
But i get this when i run my program: Axel` aler
This is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int i,n,j=0;
char text[81],cuv[44],l;
printf("Introduce-ti textul:");
gets(text);
for(i=0;i<strlen(text);i++)
{
if(text[i] != 32) {
cuv[j]=text[i];
j += 1;
} else {
n = strlen(cuv) - 1;
l= cuv[1];
cuv[1]=cuv[n-1];
cuv[n-1]=l;
printf("%s ",cuv);
strcpy(cuv,"");
j=0;
}
}
return 0;
}
First, you do not want to use gets. It was removed from the standard library because it was unsafe, use fgets instead. That being said, all you need to do is tokenize your input string into words, and then if the word is greater than 3 chars, swap the 2nd and next to last characters. One way would be:
#include <stdio.h>
#include <string.h>
#define MAXS 256
#define MAXW 64
int main (void) {
size_t len;
char str[MAXS] = {0};
char word[MAXW] = {0};
char *p = NULL;
fgets (str, MAXS, stdin); /* read input from stdin */
/* tokenize string */
for (p = strtok (str, " "); p; p = strtok (NULL, " \n"))
{
strncpy (word, p, MAXW - 1); /* copy token to word */
if ((len = strlen (word)) > 3) /* if word > 3 */
{
char tmp = word[1]; /* swap 2nd & next to last */
word[1] = word[len-2];
word[len-2] = tmp;
}
printf ("%s ", word);
}
putchar ('\n');
return 0;
}
Use/Output
$ printf "Alex are mere\n" | ./bin/swap2nd
Aelx are mree
or if you wanted to enter the text:
$ ./bin/swap2nd
Alex are mere
Aelx are mree
Second Method Using Start/End Pointers
You can also modify the original string ready be fgets in place by using nothing more than a start-pointer (p below) and end-pointer (ep below) to work your way down the string character-by-character, stopping each time the end-pointer points to a space, tab, or newline and then using the difference between the start and end pointers to check the length of the word and perform the character swap if the length is greater than 3 chars. You can work through each version and compare:
#include <stdio.h>
#define MAXS 256
int main (void) {
char str[MAXS] = {0};
char *p = NULL;
char *ep = NULL;
fgets (str, MAXS, stdin); /* read input from stdin */
p = ep = str;
while (*ep) /* for each char, if a space, tab or newline */
if (*ep == ' ' || *ep == '\t' || *ep == '\n') {
if ((ep - p) > 3) { /* if length > 3 */
char tmp = *(p + 1); /* swap chars */
*(p + 1) = *(ep - 2);
*(ep - 2) = tmp;
}
p = ++ep; /* set p to next word */
}
else
++ep;
printf ("%s\n", str);
return 0;
}
Use/Output
$ ./bin/swap2nd2
Alex are mere
Aelx are mree
Which approach you choose between these two methods, as well as the method posted by Vlad, is largely a matter of taste/choice. All are valid and are just different way of accomplishing the same thing. Let me know if you have questions.
Try the following approach
#include <stdio.h>
int main( void )
{
char s[] = "Alex Chiurtu";
char t[sizeof( s )];
size_t i = 0, j = 0;
do
{
t[i] = s[i];
if ( s[i] != ' ' && s[i] != '\t' && s[i] != '\0' )
{
++j;
}
else if ( j != 0 )
{
if ( j > 3 )
{
char c = t[i-j + 1];
t[i-j+1] = t[i-2];
t[i-2] = c;
}
j = 0;
}
} while ( s[i++] );
puts( s );
puts( t );
return 0;
}
The program output is
Alex Chiurtu
Aelx Ctiurhu
Take into account that function gets is unsafe and is not supported by the C Standard any more.
Also it is a bad idea to use magic numbers like 32. Its meaning is unclear.
In your program array cuv was not zero initialized therefore the following statement
n = strlen(cuv) - 1;
results in undefined behaviour of the program. Also it is not a good idea each time to calculate the length of the string.