Well I'm looking for a function that reduce multiple space characters ' ' in a string.
For example for string s given :
s="hello__________world____!"
The function must return "hello_world_!"
In python we can do it via regexp simply as:
re.sub("\s+", " ", s);
A version that modifies the string in place, run it on a copy if the original must be preserved:
void compress_spaces(char *str)
{
char *dst = str;
for (; *str; ++str) {
*dst++ = *str;
if (isspace(*str)) {
do ++str;
while (isspace(*str));
--str;
}
}
*dst = 0;
}
There is no such function in the C standard library. One must write a function to do so or use a third-party library.
The following function should do the trick. Use the source string as the destination pointer to perform the operation in place. Otherwise, ensure that the destination buffer is sufficiently sized.
void
simplifyWhitespace(char * dst, const char * src)
{
for (; *src; ++dst, ++src) {
*dst = *src;
if (isspace(*src))
while (isspace(*(src + 1)))
++src;
}
*dst = '\0';
}
void remove_more_than_one_space(char *dest, char *src)
{
int i, y;
assert(dest && src);
for(i=0, y=0; src[i] != '\0'; i++, y++) {
if(src[i] == ' ' && src[i+1] == ' ') {
/* let's skip this copy and reduce the y index*/
y--;
continue;
}
/* copy normally */
dest[y] = src[i];
}
dest[y] = '\0';
}
int main()
{
char src[] = "Hello World ! !! !";
char dest[strlen(src) + 1];
remove_more_than_one_space(dest, src);
printf("%s\n", dest);
}
I just made this, hope it helps.
#include<stdio.h>
#include<string.h>
#include<ctype.h>
int main()
{
char word[100];
gets(word);
//the word has more than a single space in between the words
int i=0,l,j;
l=strlen(word);
for (i=0;i<l;i++)
{
if(word[i]==' '&&word[i+1]==' ')
{
for(j=i+1;j<l;j++)
word[j]=word[j+1];
}
}
puts(word);
return 0;
}
This code is very simple and it worked like a charm for me. I don't know if this code will have some other problems I haven't come across, but for now this works.
I'm just learning C, so I'm using much more basic code. I'm reading the first chapter of "The C programming language", and I was trying to find the answer to a task set in there.
This is what I came up with:
#include <stdio.h>
int main()
{
/* Set two integers:
c is the character being assessed,
lastspace is 1 if the lastcharacter was a space*/
int c, lastspace;
lastspace = 0;
/* This while loop will exit if the character is EOF
The first "If block" is true if the character is not a space,
and just prints the character
It also tells us that the lastcharacter was not a space
The else block will run if the character is a space
Then the second IF block will run if the last character
was not also a space (and will print just one space) */
while((c = getchar()) != EOF){
if (c != ' '){
putchar(c);
lastspace = 0;
}
else {
if (lastspace != 1)
putchar(c);
lastspace = 1;
}
}
return 0;
}
Hope that helps!
Also, I am well aware that this code is perhaps not optimised, but it should be simple for a beginner like me to understand!
Thanks, Phil
another way of doing this to print only the first occurrence of space until next character comes, here is my brute force solution.
#include<stdio.h>
typedef int bool;
#define True 1
#define False 0
int main()
{
int t;
bool flag = False;
while ((t = getchar()) != EOF)
if (t == ' ' && !flag)
{
putchar(' ');
flag = True; // flag is true for the first occurence of space
}
else if(t == ' '&& flag)
continue;
else
{
putchar(t);
flag = False;
}
return 0;
}
hope it helps.
Related
I know its a question that been asked many times before, but i'm not asking for the solution itself, but to know why my solution isn't working.
this is my solution:
void delete_blanks(char *string)
{
while (*string)
{
if (*string == ' ')
*string = '\0';
*string++;
}
puts(string);
}
The program just printing blanks (" ") for every input.
while running with the debugger, I saw that *string is pointing for '\0' at the end. Is it possible to do it "in-place"?
This is the original solution found here:
void RemoveSpaces(char* source)
{
char* i = source;
char* j = source;
while(*j != 0)
{
*i = *j++;
if(*i != ' ')
i++;
}
*i = 0;
}
Here is a good in-place implementation
int main(void) {
char inStr[] = "a cat is on the moon";
int end = 0;
for (int i = 0; i < strlen(inStr); i++) {
if (inStr[i] != ' ') {
if (i != end) {
inStr[end] = inStr[i];
}
end++;
}
}
inStr[end] = '\0';
printf("%s\n", inStr);
}
Probably because you are modifying the source, the parameter passed to that function, when it looks for spaces, shortcut the source to '\0', so you are not printing the correct result. try to use other pointers like the examples you give.
char a[]="it is a sunny morning";
int j=0;
for( int i=0;i<strlen(a);i++){
if(a[i]!=' '){
a[j]=a[i];
j++;
}
}
for(int i=j;i<strlen(a);i++){
a[i]='\0';
}
printf("%s",a);
first group the letters without space then remove the letters that exceeds the space.
output
itisasunnymorning
It's unclear what you mean by "removing the blanks". If all you want to do is print the string without the spaces, you could reduce you function to this:
void delete_blanks(char *string)
{
while (*string)
{
if (*string != ' ')
putchar(*string);
string++;
}
putchar('\n');
}
If you want to remove the spaces in the underlying string it becomes a bit more complex as you would have to move characters after a ' ' to fill in the gaps. There is no 'empty character' you can insert to fill the hole in the string, you must move the remaining characters to fill it.
Basically there a 2 major things wrong with your function. You are replacing spaces with string terminating characters, signaling that the string ends here. This is not what you want to do as there might be characters after the space. In fact, if you only want to print the string you should not be modifying it at all.
When you are done iterating over the string, string points to the end of the string. Essentially passing an empty string to puts(). You need to pass the original value, before you did a lot of ++ on it, to puts()
You are also doing *string++ when you should really be doing string++. This actually works since it is parsed as *(string++) but is terrible for readability.
If you want to remove the spaces between the words of a string,
the direct answer as follows:
// #include <ctype.h>
void RemoveSpaces(char *str) {
char *strBuff = (char*) malloc(strlen(str) + 1), *p = strBuff;
while (*str) {
if (!isspace(*str)) {
*p = *str;
p++;
}
str++;
}
*p = '\0';
printf("%s\n", strBuff);
free(strBuff);
}
int main(){
RemoveSpaces("Thank you for help");
}
The Result:
Also, there is another way and gives the same result as follows:
void RemoveSpaces(char *str) {
while (*str) {
if (!isspace(*str)) {
putchar(*str);
}
str++;
}
printf("%s\n", str);
}
I tried to write a function that gets a string and creates a new string but without multiple spaces (leaving only 1 space between words).
So far I wrote this, but for some reason it crashs and the debugger shows nothing.
I also don't know where do I need to put the free function...
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* upgradestring(char* oldtext);
int main()
{
char str1[] = "Chocolate Can Boost Your Workout" ;
printf("%s\n", str1);
printf("\n%s\n", upgradestring(str1));
return 0;
}
char* upgradestring(char* oldtext)
{
int i,j, count = 1;
char *newstr;
for (i = 0; oldtext[i] != '\0'; i++)
{
if (oldtext[i] != ' ')
count++;
else if (oldtext[i - 1] != ' ')
count++;
}
newstr = (char*)malloc(count * sizeof(char));
if (newstr == NULL)
exit(1);
for (i = 0, j = 0; (oldtext[i] != '\0')|| j<(count+1); i++)
{
if (oldtext[i] != ' ')
{
newstr[j] = oldtext[i];
j++;
}
else if (oldtext[i - 1] != ' ')
{
newstr[j] = oldtext[i];
j++;
}
}
return newstr;
}
You're addressing [i-1] and it's not within the range of the original array if i==0.
Here's how you could do it:
Simply copy one by one and if the char is ' ', keep skipping while it is ' ', otherwise advance by one.
static size_t newlen(char const *o)
{
size_t r=0;
while(*o){
r++;
if(*o==' ')
while(*o==' ')
o++;
else
o++;
}
return r;
}
char *upgradestring(char const *o)
{
char *r, *p;
size_t len = newlen(o);
if( 0==(r = malloc(len+1)))
return 0;
r[len]=0;
for(p=r;*o;){
*p++=*o;
if(*o==' ')
while(*o==' ')
o++;
else
o++;
}
return r;
}
int main()
{
char str1[] = "Chocolate Can Boost Your Workout" ;
char *new;
printf("%s\n", str1);
if(0 == (new = upgradestring(str1)))
return 1;
printf("%s\n", new);
free(new);
}
Failures to allocate are best signalled by return codes (you wouldn't want a library function to abort your program if it fails).
In order to be able to free the returned string, you first must capture it in a variable.
Good attempt, but let's focus on when you need to free your memory. You allocate dynamically the memory inside the function, then call the function inside a printf, which will allow the string to print, but how will you deallocate it? Use a pointer to assign the return value of your function, print it, and then free it!
Moreover, you need to allocate space for as many characters the new string has, plus one for the null terminator, since C strings require that to work smoothly with functions coming from headers, such as printf().
Furthermore, we do not cast what malloc() returns in C, read more here.
Also this:
else if (oldtext[i - 1] != ' ')
should be written as:
else if (i != 0 && oldtext[i - 1] != ' ')
to avoid accessing oldtext[-1] which is out of bounds, when i is 0.
Lastly, the condition you used when populating the new string, would be better with a logical AND, instead of an OR, since we have to stop as soon as either condition is false (we do not want to read past the null terminator of the original string, or past the size of the new string).
Putting everything together, we:
#include <stdio.h>
#include <stdlib.h>
char* upgradestring(char* oldtext)
{
int i, j, count = 0;
// compute 'count'
for(i = 0; oldtext[i]; i++)
{
if (oldtext[i] != ' ')
count++;
else if (i != 0 && oldtext[i - 1] != ' ')
count++;
}
char* newstr = malloc(count + 1); // PLUS ONE for the null terminator
if(!newstr) // check if malloc failed
{
printf("Malloc failed\n");
return 0;
}
// populate 'newstr'. We need to stop when either condition is false
for (i = 0, j = 0; (oldtext[i]) && j<(count+1); i++)
{
// Same as your code
}
// Assign the null terminator!
newstr[j] = '\0';
return newstr;
}
int main(void) {
char str1[] = "Chocolate Can Boost Your Workout" ;
// store the result of your function into 'newstr'
char* newstr = upgradestring(str1);
// print it
printf("%s\n", newstr);
// free it, since you no longer need it!
free(newstr);
return 0;
}
Output:
Chocolate Can Boost Your Workout
#include <stdio.h>
#include <stdlib.h>
char *upgradestring(char *oldtext)
{
size_t len,src,dst,spc;
char *result;
// First pass: count needed size
for (len=src=spc=0;oldtext[src]; src++){
if (oldtext[src] != ' ') spc=0; // non-space needs space
else if(spc++) continue; // skip non first space
len++;
}
result= malloc (1+len);
// Second pass: copy(K&R style)
for (dst=src=spc=0; (result[dst] = oldtext[src]) ; src++){
if (oldtext[src] != ' ') spc=0; // non-space: rest counter
else if(spc++) continue; // skip non-first space
dst++;
}
return result;
}
Simplified version: dont calculate the size in a first pass, but start with the same size as the original, and resize after the second pass. (strdup() can be replaced by strlen+malloc+memcpy)
char * strdup(char *);
char *upgradestring2(char *oldtext)
{
size_t src,dst,spc;
char *result;
result= strdup (oldtext);
// edit the copy, skipping all spaces except the first
for (dst=src=spc=0; result[src] ; src++){
if (result[src] != ' ') spc=0; // non-space:reset counter
else if(spc++) continue; // skip space,except the first
result[dst++] = result[src]; // Copy
}
result[dst] = 0;// terminate string;
// result=realloc(result, dst+1);
return result;
}
For starters neither declaration from the header <string.h> is used in your program. Thus this directive
#include <string.h>
may be removed from the program.
According to the C Standard the function main without parameters shall be declared like
int main( void )
The function with the strange name upgradestring:) does not change the argument. Hence it should be declared like
char* upgradestring( const char* oldtext);
^^^^^
Take into account that the source string can start with blanks. In this case statements like this
else if (oldtext[i - 1] != ' ')
count++;
result in undefined behavior because there is an attempt to access memory beyond the string when i is equal to 0.
The condition
(oldtext[i] != '\0')|| j<(count+1);
should be written at least like
(oldtext[i] != '\0') && j<(count+1);
^^^
though it is enough to check the index j because it can not be greater than the length of the source string.
You forgot to append the result string with the terminating zero '\0'.
Also it is not a good idea to exit the function with this statement
exit(1);
In this case you could just return a null pointer.
And the allocated memory should be freed before exiting the program.
As it has been mentioned before a source string can start with spaces and also have a redundant trailing space. I think it will be logically consistent to exclude them from the result string.
Usually the space character is considered in pair with the tab character. Moreover C has a special function isblank declared in the header <ctype.h> that checks whether a character is a space or a blank. (As far as I know the MS VS does not support this function)
Taking all this into account the function can be defined the following way as it is shown in the demonstrative program.
#include <stdio.h>
#include <stdlib.h>
char * trim_blanks( const char *s )
{
size_t n = 0;
const char *p = s;
// skip leading blanks
while ( *p == ' ' || *p == '\t' ) ++p;
_Bool last_blank = 0;
for ( ; *p; ++p )
{
++n;
if ( ( last_blank = ( *p == ' ' || *p == '\t' ) ) )
{
while ( p[1] == ' ' || p[1] == '\t' ) ++p;
}
}
if ( last_blank ) --n;
char *q = malloc( n + 1 );
if ( q )
{
p = s;
// skip leading blanks
while ( *p == ' ' || *p == '\t' ) ++p;
size_t i = 0;
for ( ; i < n; i++, ++p )
{
q[i] = *p == '\t' ? ' ' : *p;
if ( q[i] == ' ' )
{
while ( p[1] == ' ' || p[1] == '\t' ) ++p;
}
}
q[i] = '\0';
}
return q;
}
int main(void)
{
char s[] = "\t\tChocolate \t Can \t Boost Your Workout ";
printf( "\"%s\"\n", s );
char *t = trim_blanks( s );
printf( "\"%s\"\n", t );
free( t );
return 0;
}
The program output is
" Chocolate Can Boost Your Workout "
"Chocolate Can Boost Your Workout"
I am currently creating a simple shell for homework and I've run into a problem. Here is a snippet of code with the pieces that pertain to the problem (I may have forgotten some pieces please tell me if you see anything missing):
eatWrd returns the first word from a string, and takes that word out of the string.
wrdCount, as implied, returns the number of words in a string.
if either of these codes are necessary for a response I can post them, just please tell me, I am almost 100% positive they are not the cause of the problem.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 100
int main(void)
{
char input[MAX];
char *argm[MAX];
memset(input, 0, sizeof(input));
memset(argm, 0, sizeof(argm));
while(1){
printf("cmd:\n");
fgets(input, MAX-1, stdin);
for(i=0;i < wrdCount(input); i++){
argm[i] = eatWrd(input);
}
argm[i] = NULL;
if (!strncmp(argm[0],"cd" , 2)){
chdir(argm[1]);
}
if (!strncmp(argm[0],"exit", 4)){
exit(0);
}
memset(input, 0, sizeof(input));
memset(argm, 0, sizeof(argm));
}
}
Anyways, this loop works for lots of other commands using execvp, (such as cat, ls, etc.), when I use cd, it works as expected, except when I try to exit the shell, it takes multiple exit calls to actually get out. (as it turns out, the number of exit calls is exactly equal to the number of times I call cd). It only takes one exit call when I don't use cd during a session. I'm not really sure what's going on, any help is appreciated, thanks.
Here is eatWrd:
char* eatWrd(char * cmd)
{
int i = 0; // i keeps track of position in cmd
int count = 0; // count keeps track of position of second word
char rest[MAX_LINE]; // rest will hold cmd without the first word
char * word = (char *) malloc(MAX_LINE); //word will hold the first word
sscanf(cmd, "%s", word); //scan the first word into word
// iterate through white spaces, then first word, then the following white spaces
while(cmd[i] == ' ' || cmd[i] == '\t'){
i++;
count++;
}
while(cmd[i] != ' ' && cmd[i] != '\t' && cmd[i] != '\n' && cmd[i] != '\0'){
i++;
count++;
}
while(cmd[i] == ' ' || cmd[i] == '\t'){
i++;
count++;
}
// copy the rest of cmd into rest
while(cmd[i] != '\n' && cmd[i] != '\0'){
rest[i-count] = cmd[i];
i++;
}
rest[i-count] = '\0';
memset(cmd, 0, MAX_LINE);
strcpy(cmd, rest); //move rest into cmd
return word; //return word
}
And here is wrdCount:
int wrdCount(char *sent)
{
char *i = sent;
int words = 0;
//keep iterating through the string,
//increasing the count if a word and white spaces are passed,
// until the string is finished.
while(1){
while(*i == ' ' || *i == '\t') i++;
if(*i == '\n' || *i == '\0') break;
words++;
while(*i != ' ' && *i != '\t' && *i != '\n' && *i != '\0') i++;
}
return words;
}
This variation on your code works for me:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#define MAX 100
char *eatWrd(char **line) {
char *next_c = *line;
char *word_start = NULL;
while (isspace(*next_c)) next_c += 1;
if (*next_c) {
word_start = next_c;
do {
next_c += 1;
} while (*next_c && ! isspace(*next_c));
*next_c = '\0';
*line = next_c + 1;
}
return word_start;
}
int main(void)
{
char input[MAX];
char *argm[MAX];
while(1) {
int word_count = 0;
char *next_input = input;
printf("cmd:\n");
fgets(input, MAX, stdin);
do {
argm[word_count] = eatWrd(&next_input);
} while (argm[word_count++]);
/* The above always overcounts by one */
word_count -= 1;
if (!strcmp(argm[0], "cd")){
chdir(argm[1]);
} else if (!strcmp(argm[0], "exit")) {
exit(0);
}
}
}
Note my variation on eatWrd(), which does not have to move any data around, and which does not require pre-parsing the string to determine how many words to expect. I suppose your implementation would be more complex, so as to handle quoting or some such, but it could absolutely follow the same general approach.
Note, too, my correction to the command-matching conditions, using !strcmp() instead of strncmp().
I'm writing a program in which a function that reverses each word in a string. When I call the function, it will pass the pointer to source string and then return the pointer to modified string.
input: Why always me?
output: yhW syawla ?em
But for some reason, it is not working. No errors. And logic seemed fine to me (i'm not that good with c, btw)
Here's my code:
char *reverse_words(char *source_string)
{
char *startW, *endW;
startW = source_string;
while(*startW != '\0')
{
while(*startW == ' ')
startW++; //Skip multiple spaces in the beginning
endW = startW;
while(*endW != ' ' || *endW != '\0')
endW++;
char *_start = startW;
char *_end = endW - 1;
char temp;
while(_end > _start)
{
temp = *_start;
*_start++ = *_end;
*_end++ = temp;
}
startW = endW;
}
return source_string;
}
void main() {
char *s;
s = malloc(256);
gets(s);
printf("%s\n", s);
char *r = reverse_words(s);
printf("\nReversed String : %s",r);
free(s);
free(r);
}
Also, i'm using codeblocks IDE. After I input my string, it prints it back (scanf and printf in main) and after that, the program stops working.
Any help would be appreciated.
First,
while(*endW != ' ' || *endW != '\0')
is an infinite loop, try this instead:
while(*endW != ' ' && *endW != '\0')
Second,
*_end++ = temp;
should be this:
*_end-- = temp;
In the innermost while(_end > _start) loop you increment both _start and _end. So the condition will never become false. (Well, not until _end overflows.)
I'd recommend figuring out how to do step-by-step debugging in your IDE. Then you can easily understand what exactly goes wrong in a case like this, without simulating the execution in your head.
#include <stdio.h>
#include <stdlib.h>
char *reverse_words(const char *source_string){
const char *startW, *endW;
char *p, *rev = malloc(256);
startW = source_string;
p = rev;
while(*startW != '\0'){
while(*startW == ' ')
*p++ = *startW++;
if(!*startW)
break;
endW = startW;
while(*endW != ' ' && *endW != '\0')
endW++;
const char *endW2 = endW;
do{
*p++ = *--endW;
}while(startW!=endW);
startW = endW2;
}
*p = '\0';
return rev;
}
int main() {
char s[256];
scanf("%255[^\n]", s);
printf("%s,\n", s);
char *r = reverse_words(s);
printf("\nReversed String : %s.", r);
free(r);
return 0;
}
char *p = " woohoo";
int condition = /* some calculation applied to p */
/* to look for all 0x20/blanks/spaces only */
if (condition)
{
}
else
{
printf("not ");
}
printf("all spaces\n");
One-liner:
int condition = strspn(p, " ") == strlen(p);
Slightly more optimized:
int condition = p[strspn(p, " ")] == '\0';
If you want a fast way to do this, the best thing that comes to my mind is to write your own function (I assume you only search for ' ' characters) .
int yourOwnFunction(char *str, char c) {
while(*str != '\0' && *str != c) {
str++;
}
return *str == '\0';
}
So you just have to test
if(yourOwnFunction(p,' ')) {
...
} else {
...
}
Correct me if I misunderstood something :)
Btw I didn't test it, but this should be in the worst case as fast as the other proposed method. If you just want a one-liner strager's (elegant) solution is the way to go!