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.
Related
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.
So I am trying to write a program that takes a sentence and prints it out from the third word. Ex one two three four should print out three four.
Now this code works but I have no idea why as the logic under the else statement make it seem like it should not.
Would be thankful if someone could explain why it works like this.
Here is the code:
#include <stdio.h>
#include <string.h>
#define SIZE 100
int main(void) {
char arr[SIZE];
char *point;
char again = 'n';
do {
int count = 0;
for (int i = 0; i < SIZE; i++) {
arr[i] = '\0';
}
printf("Enter a sentence:");
gets(arr);
for (int i = 0; i < SIZE; i++) {
if (arr[i] == ' ') {
count++;
}
}
if (count < 2) {
printf("The sentence is to short!\n");
} else {
count = 1; //shouldn't this be count = 0?
for (int i = 0; i < SIZE; i++) {
if (arr[i] == ' ') {
count++;
}
if (count == 2) {
point = &arr[i + 2]; //shouldn't this be [i+1]?
}
}
printf("%s\n", point);
}
printf("Do you want to try again? (y/n)");
scanf("%c", &again);
while (getchar() != '\n');
} while (again == 'y' || again == 'Y');
return 0;
}
Your code has multiple problems:
You should never use gets(). This function has been removed from the C Standard because it cannot be given the maximum number of characters to write to the destination buffer, so any sufficiently long line from the input stream will cause undefined behavior. This is a classic security flaw. Use fgets() instead.
The loop while (getchar() != '\n'); will cause an infinite loop if there is no newline before the end of file, which will happen if you redirect input an empty file. You should also check for EOF:
while ((c = getchar()) != EOF && c != '\n')
continue;
There is no need to initialize the destination array, but you should check if the input operation succeeded, by comparing the return value of fgets() to NULL.
When iterating through the array to count spaces, you should stop at the null terminator. The contents of the array beyond the null terminator is indeterminate after the input operation, even if you initialized it prior to the call.
The code to skip the words is cumbersome and not easy to validate. Indeed point = &arr[i+2]; should be point = &arr[i+1].
words might be separated by more than one space, and initial spaces should be ignored.
Here is a corrected version using string functions strspn and strcspn to skip blanks and non-blanks:
#include <stdio.h>
#include <string.h>
#define SIZE 100
#define WS " \t\n\r\v\f" /* white space characters */
int main(void) {
char arr[SIZE];
char *p;
for (;;) {
printf("Enter a sentence:");
if (fgets(arr, sizeof arr, stdin) == NULL)
break;
p = arr;
p += strspn(p, WS); /* skip initial spaces */
p += strcspn(p, WS); /* skip first word */
p += strspn(p, WS); /* skip spaces */
p += strcspn(p, WS); /* skip second word */
p += strspn(p, WS); /* skip spaces */
if (*p == '\0') {
printf("The sentence is too short!\n");
} else {
printf("%s", p);
}
printf("Do you want to try again? (y/n)");
if (fgets(arr, sizeof arr, stdin) == NULL)
break;
if (*arr != 'y' && *arr != 'Y')
break;
}
return 0;
}
Another simple way to handle the word count is to walk-a-pointer down your string in a state loop keeping track of whether you are in a word (if so increase word count), otherwise you are not in a word and just keep walking down the buffer (i.e. iterating over each char) until you find the next word (or end of string).
The logic is simple, after filling your buffer, and setting a pointer to it, e.g.
#define MAXC 1024 /* buffer size (don't skimp) */
#define NWORD 3 /* output beginning with NWORD word */
...
char buf[MAXC] = "", /* buffer to hold line */
*p = buf; /* pointer to walk down buffer */
int n = 0, /* word counter */
in = 0; /* flag - in a word */
Just loop checking each character with isspace() and handle setting your in flag to either 1 (in word) or 0 (in space before or between words) incrementing your counter each time you go in a new word, and exiting the loop when your count reaches 3, e.g.
for (; *p; p++) { /* loop over each char */
if (!in && !isspace(*p)) { /* if not in word and not space */
in = 1, n++; /* set in flag, increment words */
if (n == NWORD) /* if 3rd word, break */
break;
}
else if (isspace(*p)) /* if space */
in = 0; /* unset in flag */
}
Putting it altogether in a short example, you could do something similar to the following which takes input until the Enter key is pressed alone on an empty line, and outputting each sentence entered beginning with the third-word, or displaying the error "too few words." if a sentence with less that three words is entered, e.g.
#include <stdio.h>
#include <ctype.h>
#define MAXC 1024 /* buffer size (don't skimp) */
#define NWORD 3 /* output beginning with NWORD word */
int main (void) {
for (;;) { /* loop continually until empy-line */
char buf[MAXC] = "", /* buffer to hold line */
*p = buf; /* pointer to walk down buffer */
int n = 0, /* word counter */
in = 0; /* flag - in a word */
fputs ("\nenter sentence: ", stdout); /* prompt */
if (!fgets (buf, MAXC, stdin) || *buf == '\n') { /* read line */
puts ("all done!");
break;
}
for (; *p; p++) { /* loop over each char */
if (!in && !isspace(*p)) { /* if not in word and not space */
in = 1, n++; /* set in flag, increment words */
if (n == NWORD) /* if 3rd word, break */
break;
}
else if (isspace(*p)) /* if space */
in = 0; /* unset in flag */
}
if (n == NWORD) /* if 3 or more words */
fputs (p, stdout);
else /* other wise handle error */
fputs ("too few words.\n", stderr);
}
return 0;
}
Example Use/Output
$ ./bin/thirdword
enter sentence: one two three four five
three four five
enter sentence: one two
too few words.
enter sentence: one two three
three
enter sentence:
all done!
Look things over and let me know if you have further questions.
count = 1; //shouldn't this be count = 0? and point = &arr[i + 2]; //shouldn't this be [i+1]?
The following answers both questions.
count count count count
0 1 2 3
one two three four
i+0 i+1 i+2 i+3
point = &arr[i + 2]; along with printf("%s\n", point); says that print all characters from address of arr[i + 2] till seeing \0 character
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]);
My program aims to print each word in the sentence on a separate line.but I should print it with %s not %c! I already try to implement it but the program does not give me a correct output ! my idea is when you find null character
1- print the word
2- return the index of the temp array to 0 and store a new word
int main () {
char sen[100];
char cpy [100];
printf("Entter a sentence ");
gets(sen);
int len = strlen(sen);
int i = 0;
int k =0;
for (i=0 ; i<len;i++)
{
if (sen[i]!='\0')
{
cpy[k++]+=sen[i];
}
else{
printf("%s\n",cpy);
k=0;}
}
}
You confound null character and space character. Null character \0 stands for "end of string" : the strlen function returns the number of characters before the first \0.
In your forloop, you want to display each word separated by so you have to test with the caracter instead of \0.
Also to correctly display your string you have to end the string with the \0 character. So before the instruction printf you must do cpy[k] = '\0';.
if (sen[i]!='\0') will always be true as pointed by Julien Vernay, you need if (sen[i]!= ' ') instead of if (sen[i]!='\0'), as there are spaces between words, to seprate them.
Also in cpy[k++]+=sen[i]; you are adding sen[i] to cpy[k++] which seams weird, I think what you need is cpy[k++] = sen[i];
Modify your loop as follows...
for (i=0 ; i<len; i++) {
int flag = 0;
while(sen[i] == ' ') i++; // multiple spaces
while(sen[i] != ' ' && sen[i] != '\0') {
cpy[k++] = sen[i];
flag = 1;
i++;
}
if(flag) {
cpy[k] = '\0';
printf("%s\n",cpy);
k=0;
}
}
You can have to not bother with doing a copy - all you need to do is essentially replace spaces with new lines. So here is the code to do this:
#include <stdio.h>
int main()
{
char sen[100];
bool last_char_space = true;
printf("Please enter a sentence: ");
fflush(stdout);
fgets(sen, 100, stdin);;
for (int loop = 0; sen[loop]; ++loop) { // send[loop] is true until end of string - saves repeatedly calling strlen
if (send[loop] == ' ') { // A space
if (last_char_space) { // Last character not a space, put new line
fputc('\n', stdout);
}
last_char_space = true; // Record the fact that we are between words
} else {
fputc(sen[loop], stdout); // Not a space - print it
last_char_space = false; // We are working on a word
}
}
return 0;
}
this is my first post in this forum so please be patient.
I need to make a short programm, where the user can enter 2 strings which should be attached afterwards.
I already got this code below (I am not allowed to use other "includes").
What I need to know is: How can I deny any spaces which the user will enter?
Example: 1. String "Hello " | 2. String "World" Result should be "HelloWorld" instead of "Hello World".
#include <stdio.h>
void main()
{
char eingabe1[100];
char eingabe2[100];
int i = 0;
int j = 0;
printf("Gib zwei Wörter ein, die aneinander angehängt werden sollen\n");
printf("1. Zeichenkette: ");
gets(eingabe1);
printf("\n");
printf("2. Zeichenkette: ");
gets(eingabe2);
printf("\n");
while (eingabe1[i] != '\0')
{
i++;
}
while (eingabe2[j] != '\0')
{
eingabe1[i++] = eingabe2[j++];
}
eingabe1[i] = '\0';
printf("Nach Verketten: ");
puts(eingabe1);
}
You have to filter out the spaces as you copy your strings.
You have two string indices, i for the first string and and j for the second string. You could make better use of these indices if you used i for the reading position (of both strings subsequently; you can "reuse" loop counters in independent loops) and j for the writing position.
Here's how. Note that the code attempts to prevent buffer overflow by only adding characters if there is space in the string. This check needs only to be done when copying the second string, because j <= i when you process the first string.
#include <stdio.h>
int main()
{
char str1[100] = "The quick brown fox jumps over ";
char str2[100] = "my big sphinx of quartz";
int i = 0;
int j = 0;
while (str1[i] != '\0') {
if (str1[i] != ' ') str1[j++] = str1[i];
i++;
}
i = 0;
while (str2[i] != '\0') {
if (str2[i] != ' ' && j + 1 < sizeof(str1)) str1[j++] = str2[i];
i++;
}
str1[j] = '\0';
printf("'%s'\n", str1);
return 0;
}
In addition to avoiding spaces between your two words, you also have to avoid the newline ('\n') character placed in the input buffer by the user pressing Enter. You can do that with a simple test after you have read the line with fgets() NOT gets(). gets() is no longer part of the standard C library and should not be used due to insecurity reasons. Plus fgets provides simple length control over the number of characters a user may enter at any time.
Below, you run into trouble when you read eingabe1. After the read, eingabe1 contains a '\n' character at its end. (as it would using any of the line-oriented input functions (e.g. getline(), fgets(), etc) To handle the newline, you can simply compare its length minus '1' after you loop over the string to find the nul character. e.g.:
if (eingabe1[i-1] == '\n') i--; /* remove trailing '\n', update i */
By simply reducing the index 'i', this will guarantee that the concatenation with eingabe2 will not have any spaces or newline characters between the words.
Putting the pieces together, and using fgets in place of the insecure gets, after #define MAX 100'ing a constant to prevent hardcoding your array indexes, you could come up with something similar to:
#include <stdio.h>
#define MAX 100
int main (void)
{
char eingabe1[MAX] = {0};
char eingabe2[MAX] = {0};
int i = 0;
int j = 0;
printf("Gib zwei Wörter ein, die aneinander angehängt werden sollen\n");
printf("1. Zeichenkette: ");
/* do NOT use gets - it is no longer part of the C library */
fgets(eingabe1, MAX, stdin);
putchar ('\n');
printf("2. Zeichenkette: ");
/* do NOT use gets - it is no longer part of the C library */
fgets(eingabe2, MAX, stdin);
putchar ('\n');
while (eingabe1[i]) i++; /* set i (index) to terminating nul */
if (i > 0) {
if (eingabe1[i-1] == '\n') i--; /* remove trailing '\n' */
while (i && eingabe1[i-1] == ' ') /* remove trailing ' ' */
i--;
}
while (eingabe2[j]) { /* concatenate string - no spaces */
eingabe1[i++] = eingabe2[j++];
}
eingabe1[i] = 0; /* nul-terminate eingabe1 */
printf("Nach Verketten: %s\n", eingabe1);
return 0;
}
Output
$ ./bin/strcatsimple
Gib zwei Wörter ein, die aneinander angehängt werden sollen
1. Zeichenkette: Lars
2. Zeichenkette: Kenitsche
Nach Verketten: LarsKenitsche
Let me know if you have any further questions. I have highlighted the changes with comments above.
/**
return: the new len of the string;
*/
int removeChar(char* string, char c) {
int i, j;
int len = strlen(string)+1; // +1 to include '\0'
for(i = 0, j = 0 ; i < len ; i++){
if( string[i] == c )
continue; // avoid incrementing j and copying c
string[ j ] = string[ i ]; // shift characters
j++;
}
return j-1; // do not count '\0';
}
int main(){
char str1[] = "sky is flat ";
char str2[100] = "earth is small ";
strcat( str2, str1 );
printf("with spaces:\n\t'%s'\n", str2) ;
removeChar(str2, ' ');
printf("without spaces:\n\t'%s'\n", str2 );
}
/**
BONUS: this will remove many characters at once, eg "\n \r\t"
return: the new len of the string;
*/
int removeChars(char* string, char *chars) {
int i, j;
int len = strlen(string);
for(i = 0, j = 0 ; i < len ; i++){
if( strchr(chars,string[i]) )
continue; // avoid incrementing j and copying c
string[ j ] = string[ i ]; // shift characters
j++;
}
string[ j ]=0;
return j;
}
Thank you everyone for all the answers.
I got the solution now.
I read some advices from you and will try to remember for the future.
See the code below:
(Excuse me for the strange names for the variables, I use german words)
A few notices:
I am not allowed to use library functions
I am not allowed to use fgets for some reasons as a trainee
#include <stdio.h>
void main()
{
char eingabe1[100];
char eingabe2[100];
int i = 0;
int j = 0;
printf("gib zwei wörter ein, die aneinander angehängt werden sollen\n");
printf("1. zeichenkette: ");
gets(eingabe1);
printf("\n");
printf("2. zeichenkette: ");
gets(eingabe2);
printf("\n");
//Attach Strings
while (eingabe1[i] != '\0')
{
i++;
}
while (eingabe2[j] != '\0')
{
eingabe1[i++] = eingabe2[j++];
}
//Remove Space
eingabe1[i] = '\0';
i = 0;
j = 0;
while (eingabe1[i] != '\0')
{
if (eingabe1[i] != 32)
{
eingabe2[j++] = eingabe1[i];
}
i++;
}
eingabe2[j] = '\0';
printf("Nach verketten: ");
puts(eingabe2);
}
Sounds like homework to me.
I just wanted to mention that you probably shouldn't use sizeof() on strings these days because there may be multibyte characters in there. Use strlen() instead. The only time sizeof() would be appropriate is if you're going to malloc() a certain number of bytes to store it.
I write little loops fairly often to do low level text stuff one character at a time, just be aware that strings in C usually have a 0 byte at the end. You have to expect to encounter one and be sure you put one on the output. Space is 0x20 or decimal 32 or ' ', it's just another character.