I'm having trouble looping through a string and replacing instances of a character with a new character. I'm attempting to do so with a function that I've called replace.
// C program to replace all occurrences of a character with another in a string
#include <stdio.h>
#include <string.h>
/* Function declaration */
void replace(char *string, char toReplace, char replaceWith);
int main()
{
char string[100];
char toReplace, replaceWith;
printf("Enter any string: ");
scanf("%s", string);
printf("Enter character to replace: ");
scanf("%c\n", &toReplace);
getchar();
printf("Enter character to replace '%c' with: ", toReplace);
scanf("%c\n", &replaceWith);
replace(string, toReplace, replaceWith);
// print new string
printf("%s\n", string);
return 0;
}
// Replaces the all occurrence of a character with another in given string.
void replace(char *string, char toReplace, char replaceWith)
{
for (int i = 0; i <= strlen(string); i++)
{
if (string[i] == toReplace)
{
string[i] = replaceWith;
}
}
}
Snippets of code causing me the most grief are:
printf("Enter character to replace '%c' with: ", toReplace);
Does not print what I expect it to.
if (string[i] == toReplace)
Treats string[i] as the entire string, and not the individual members of the string.
Changing
scanf("%c\n", &toReplace);
to
scanf(" %c", &toReplace); helped, as this now ignores leading whitespace.
Your replace function is OK except for a few details:
you should not recompute the length of the string at each iteration, especially as the compiler cannot assume the string to be constant since it gets modified inside the loop.
the test should be i < len where len is the length of the string. It seems incorrect to test the null terminator for replacement.
i should be defined with type size_t instead of int.
The problem you observe is linked to your usage of scanf():
"%c\n" will read the pending newline from stdin and then consume any subsequent white-space, which should not occur as the user typed the character they were prompted for. The next call will read this character, consume the newline and leave the second character typed pending in stdin. You should use scanf(" %c", &toReplace) instead.
note also that scanf("%s", string); will stop at the first white-space character and may cause a buffer overflow. Using fgets() seems a better approach for this.
Here is a modified version:
#include <stdio.h>
#include <string.h>
/* Function declaration */
void replace(char *string, char toReplace, char replaceWith);
int main() {
char string[100];
char toReplace, replaceWith;
printf("Enter any string: ");
if (!fgets(string, sizeof string, stdin))
return 1;
printf("Enter character to replace: ");
if (scanf(" %c", &toReplace) != 1)
return 1;
printf("Enter character to replace '%c' with: ", toReplace);
if (scanf(" %c", &replaceWith) != 1)
return 1;
replace(string, toReplace, replaceWith);
// print new string
printf("%s", string);
return 0;
}
// Replaces the all occurrence of a character with another in given string.
void replace(char *string, char toReplace, char replaceWith) {
for (size_t i = 0, len = strlen(string); i < len; i++) {
if (string[i] == toReplace) {
string[i] = replaceWith;
}
}
}
Related
#include <stdio.h>
#include <ctype.h>
int main() {
char str[100];
char out[] = "exit";
do {
printf("Enter a string: ");
scanf("%s", str);
// some if else statement here
} while (toupper(str[3]) != toupper(out[3]));
}
I put the index 3 because if I put the index 0 there, the code will terminate if the entered string starts with letter e. I tried the while loop but it does not work for me. Also I want to print a prompt message that says "detected terminate keyword" after entering the word "exit" and then terminates the loop.
You will also notice the toupper() function. I used it there because I want my loop to be case insensitive, so regarless of lowercase or uppercase or combination of both, the loop should terminate when the word "exit" is entered.
toupper(str[3]) != toupper(out[3]) will compare the upper case 4th letter of str and out, so the loop will iterate till str[3] is 'T'. You want to use strcasecmp(str, out) instead. Remember to #include <strings.h>.
There are multiple problems:
it is confusing for a function isPalindrome() to return 0 for true.
to avoid undefined behavior on negative char values, a char argument to toupper should be cast as (unsigned char).
the test for the exit keyword is incorrect. You exit if the fourth letter is a t or a T. You should use strcasecmp to test for the exit word.
scanf("%s", str) has potential undefined behavior if the user enters a word with more than 99 bytes. Use scanf("%99s", str) and test the return value: it must be 1 for a successful conversion.
instead of a confusing do / while loop, use a for (;;) loop (also known as for ever loop), and test for 2 exit conditions: scanf() failure to read a word and reading the word exit.
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int isPalindrome(const char *str) {
size_t len = strlen(str);
for (size_t i = 0; i < len; i++) {
if (toupper((unsigned char)str[i]) != toupper((unsigned char)str[len - i - 1]))
return 0;
}
return 1;
}
int main() {
char str[100];
for (;;) {
printf("Enter a string: ");
if (scanf("%99s", str) != 1)
break;
if (!strcasecmp(str, "exit"))
break;
if (isPalindrome(str)) {
printf("%s is a palindrome!\n\n", str);
} else {
printf("%s is not a palindrome!\n\n", str);
}
}
return 0;
}
I put the index 3 because if I put the index 0 there, the code will terminate if the entered string starts with letter e
Exactly, and the code:
while (toupper(str[3]) != toupper(out[3])
Suffers from the same problem, any input with a t as its 4th character index 3 will match and the loop will end, you are comparing a specific character of the string, not the string itself. You can use strcasecmp to assess if the input is indeed exit and ignore casing.
Furthermore using %s specifier is not good, you run the risk of overrunning the destination buffer. You should use a width, %99s for a 100 characters buffer to leave space for the nul byte, if possible consider using fgets instead.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main() {
char str[100];
char out[] = "exit";
do {
printf("Enter a string: ");
scanf(" %99s", str); // space before specifier to clean leading whitespaces
// some if else statement here
} while (strcasecmp(str, out) != 0);
puts("Detected terminate keyword. Goodbye!");
}
char *removeLastChar(char *str, char ch)
{
size_t len;
if(str)
{
len = strlen(str);
if(str[len - 1] == ch) str[len -1] = 0;
}
return str;
}
char *strlwr(char *str)
{
char *wrk = str;
if(str)
{
while(*wrk)
{
*wrk = tolower((unsigned char)*wrk);
wrk++;
}
}
return str;
}
int main(void)
{
char str[100];
const char *out = "exit";
int x = 0;
do
{
printf("Enter a string: ");
if(!fgets(str, sizeof(str), stdin)) break;
removeLastChar(str, '\n');
printf("You entered: \"%s\"\n:", str);
} while (strcmp(strlwr(str), out));
}
My program skips the next input after 1 pass through it. I have read the threads on removing the newline character that fgets has, but nothing that was suggested worked. Is there anything that would work with microsoft visual studio? The best suggestion was "words[strcspn(words, "\r\n")] = 0;" and this did not remove the new line, unless I am formatting it incorrectly. I am not allowed to use the strtok function.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 50
#define STOP "quit\n"
char *copywords(char *dest, const char *source, size_t n);
int main(void)
{
char words[50];
char newwords[50];
size_t num;
for (;;) {
printf("\nType a word, or type 'quit' to quit: ");
(fgets(words, SIZE, stdin));
if (strcmp(words, STOP) == 0) {
printf("Good bye!\n");
return 0;
}
printf("Type the # of chars to copy: ");
scanf_s("%d", &num);
copywords(newwords, words, num);
printf("The word was %s\n", words);
printf("and the copied word is %s", newwords);
}
}
char *copywords(char *dest, const char *source, size_t n) {
size_t i;
for (i = 0; i < n && source[i] != '\0'; i++) {
dest[i] = source[i];
}
dest[i] = '\0';
return dest;
}
The problem is that you leave the \n on the input when you call scanf. i.e. the user types number[return]. You read the number. When you loop around and call fgets agains the return is still waiting to be read so thats what fgets gets and it returns immediately.
I would probably just call fgets the second time you want to read input as well and then use sscanf to read from the string. i.e.
printf("Type the # of chars to copy: ");
fgets(buffer, ...)
sscanf(buffer, "%d", ...)
As an aside I would also say to check return values as it is easy for fgets or *scanf to fail.
My program skips the next input after 1 pass through it.
If I understand you correctly, the problem is that scanf_s (which I assume is like the C standard's scanf) will read the digits into num, but scanf won't remove the following newline from stdin, and so in the next iteration of the loop fgets will see that newline and behave as if it had seen a blank line.
I have usually avoided scanf for this reason and instead read a line into a buffer and then parse it. For example:
char buf[50];
...
fgets(buf,sizeof(buf),stdin);
sscanf(buf,"%d",&num);
(I'd also recommend adding a whole lot more error checking throughout.)
Here's a straightforward solution.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 50
#define STOP "quit\n"
char *copywords(char *dest, const char *source, size_t n);
int main(void)
{
char words[50];
char newwords[50];
size_t num, run = 0;
for (;;) {
printf("\nType a word, or type 'quit' to quit: ");
if(run)
getchar();
(fgets(words, SIZE, stdin));
if (strcmp(words, STOP) == 0) {
printf("Good bye!\n");
return 0;
}
printf("Type the # of chars to copy: ");
scanf("%d", &num);
copywords(newwords, words, num);
printf("The word was %s\n", words);
printf("and the copied word is %s", newwords);
run = 1;
}
}
char *copywords(char *dest, const char *source, size_t n) {
size_t i;
for (i = 0; i < n && source[i] != '\0'; i++) {
dest[i] = source[i];
}
dest[i] = '\0';
return dest;
}
Since we know there will be an extra '\n' character left in the stream due to the scanf, just take it out.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int main(){
char str [1000] = "";
char ch = 'M';
char *findM;
printf("Enter a line of text\n");
scanf("%s", str);
findM = strchr(str, ch);
printf("string after %c is %s ", ch, findM);
return 0;
}
The input to the program is "My name is Steve", and the output of this program becomes, string after M is (null) Why is this occurring?
As mentioned in one of the comments, scanf("%s", str) reads until it finds a trailing white space. In your input "My name is Steve" scanf will read up to My since there is a space after My.
Assuming that your input only contains numbers,letters, and spaces you could try the following:
int main()
{
char str[1000] = "";
char ch = 'M';
char *findM;
printf("Enter a line of text\n");
scanf("%999[0-9a-zA-Z ]", str); // Get all alphanumerics and spaces until \n is found
findM = strchr(str, ch);
findM++; // Increment the pointer to point to the next char after M
printf("string after %c is %s ", ch, findM);
return 0;
}
If you are not required to use scanf(), I will recommend staying away from scanf() and using fgets() instead:
int main()
{
char str[1000] = "";
char ch = 'M';
char *findM;
printf("Enter a line of text\n");
fgets(str, sizeof(str), stdin); // Get the whole string
findM = strchr(str, ch);
findM++; // Increase the counter to move to the next char after M
printf("string after %c is %s ", ch, findM);
return 0;
}
You would get null if the method does not find any matches, it is possible that your input does not have 'M'
for more details : http://www.cplusplus.com/reference/cstring/strchr/
Probably your str variable doesn't contain the char 'M' in the first word - The strchr(string, char) function returns null if no match is found and cuts off the input string after the first whitespace (excluding leading whitespaces). As user3121023 mentioned in their comment, use fgets instead to capture multi-word input.
strchr() is considering ' ' (space )as a delimiter so give you input withiut a space it works fine ..
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int main()
{
char str [1000] = "";
char ch = 'M';
char *findM;
printf("Enter a line of text\n");
scanf("%s", str);
findM = strchr(str, ch);
if(findM)
printf("string after %c is %s ", ch, findM);
else
printf("Character not found ...\n");
return 0;
}
So, I want to create a function which creates and returns a dynamic string based on a string s without characters c. Now, I want to be able to remove all of the desired characters, no matter the case. Additionally, the original string entered by the user should remain unchanged. Here's my attempt, it keeps telling me about an error at line 12 (noted in the comments).
One more thing: I'm not sure if I wrote the remove function well, I think it should work? All of the pointers confused me a little bit.
#include <stdio.h>
#include <stdlib.h>
char * remove(char *s, char c);
int strlen(char *s);
int main() {
char s[16], c, n[16];
printf("Please enter string: ");
scanf("%s", s);
printf("Which character do you want to remove? ");
scanf("%c", &c);
n = remove(s, c); // Place the new string in n so I wouldn't change s (the error)
printf("The new string is %s", n);
return 0;
}
int strlen(char *s)
{
int d;
for (d = 0; s[d]; d++);
return d;
}
char * remove(char *s, char c) {
char str[16], c1;
int i;
int d = strlen(s);
str = (char)calloc(d*sizeof(char)+1);
// copying s into str so I wouldn't change s, the function returns str
for (i = 0; i < d; i++) {
while(*s++ = str++);
}
// if a char in the user's string is different than c, place it into str
for (i = 0; i < d; i++) {
if (*(s+i) != c) {
c1 = *(s+i);
str[i] = c1;
}
}
return str; // the function returns a new string str without the char c
}
You declared n as 16-element array of char type:
char n[16];
So you cannot do:
n = remove(s, c);
because n is a const pointer.
Also your remove function returns a pointer to its local array, which gets destroyed as soon as your function returns. Better declare remove as
void remove(char *to, char *from, char var);
and pass n as the first parameter.
There ware so many mistakes in your program it was easier to rewrite and show you, with added comments. Note that scanf("%s... will accept only a single word, not a sentence (it stops at the first whitespace). And note that the newline will be left in the input buffer for scanf("%c... to read unless you add a space, as advised.
#include <stdio.h>
void c_remove(char *n, char *s, char c) { // renamed because remove() is predefined
while (*s) { // no need for strlen()
if (*s != c) // test if char is to be removed
*n++ = *s; // copy if not
s++; // advance source pointer
}
*n = '\0'; // terminate new string
}
int main(void) { // correct signature
char s[16], c, n[16];
printf("Please enter string: ");
scanf("%s", s);
printf("Which character do you want to remove? ");
scanf(" %c", &c); // the space before %c cleans off whitespace
c_remove(n, s, c); // pass target string pointer too
printf("The new string is %s", n);
return 0;
}
Program sessions:
Please enter string: onetwothree
Which character do you want to remove? e
The new string is ontwothr
Please enter string: onetwothree
Which character do you want to remove? o
The new string is netwthree
I am in the process of writing a C program that parses a string and tokenizing it by breaking the string characters into words that are seperated by white space. My question is when i run my current program:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char input[20];
printf("Please enter your word:\n");
scanf("%c", &input);
printf("%c", input[1]);
return 0;
}
If i was to enter the word "This", i would expect to get back "h" when i run the program but instead i get a downwards pointing arrow. However, when the input is set to print out input[0] i get back a "T".
Edit: I have modified my code so that it prints out the whole string now which i will show below
int main()
{
char input[20];
printf("Please enter your words:\n");
scanf("%s", input);
printf("%s", input);
return 0;
}
My goal is to be able to break that string into chars that i can search through to find whitespace and thus being able to isolate those words for example, if my input was "This is bad" i'd like the code to print out
This
is
bad
Edit:
I have modified my code to fit one of these answers but the problem i run into now is that it won't compile
int main()
{
char input[20];
printf("Please enter your words:\n");
size_t offset = 0;
do
{
scanf("%c", input + offset);
offset++;
}
while(offset < sizeof(input) && input[offset - 1] != '\n');
}
printf("%c", input[]);
return 0;
Problems:
1) scanf("%c", input); only set the first element of the array input.
2) printf("%c", input[1]); prints the second element of the array input, which has uninitialized data in it.
Solution:
Small state machine. No limit on string size like 20.
#include <ctype.h>
#include <stdio.h>
int main() {
int ch = fgetc(stdin);
while (ch != EOF) {
while (isspace(ch)) {
// If only 1 line of input allowed, then add
if (ch == '\n') return 0;;
ch = fgetc(stdin);
}
if (ch != EOF) {
do {
fputc(ch, stdout);
ch = fgetc(stdin);
} while (ch != EOF && !isspace(ch));
fputc('\n', stdout);
}
}
return 0;
}
scanf("%c", &input); does not do what you think it does.
First of all, %c scans only a single character: http://www.cplusplus.com/reference/cstdio/scanf/
Second, array's name is already a pointer to it's first element, so stating &input you make a pointer to a pointer, so instead of storing your character in array's first element you store it in pointer to the array which is a very bad thing.
If you really want to use scanf, I recommend a loop:
size_t offset = 0;
do
{
scanf("%c", input + offset);
offset++;
}
while(offset < sizeof(input) && input[offset - 1] != '\n');
Using scanf("%s", input") leaves you vulnerable to buffer overflow attacks if the word is longer than 20 characters http://en.wikipedia.org/wiki/Buffer_overflow
In my example I assumed, that you want to finish your word with a newline character.
EDIT: In scanf documentation is also a good example:
scanf("%19s", input);
It scans no more than 19 characters, which also prevent buffer overflow. But if you want to change input size, you have to change it two places.
You can use
char * strtok ( char * str, const char * delimiters );
to tokenize your string. If you have your input in input[] array and want to tokenize the string accoring to whitespace character, you can do the following :
char *ptr;
ptr = strtok(input, " ");
while(ptr != NULL) {
printf("%s\n", ptr);
ptr = strtok(NULL, " ");
}
Only the first call to strtok() requires the character array as input. Specifying NULL in the next calls means that it will operate on the same character array.
Your scanf only picks up the first character, input[1] contains random garbage. Use scanf("%19s", input) instead.