void r(char *str)
{
char *new = str;
while (*str != '\0') {
if (*str != ' ') *(new++) = *str;
str++;
}
*new = '\0';
}
I have this function but i don't understand the code after the if statement .I would be grateful if somebody could explain it to me.
This function is stripping spaces out of the passed in value str.
*(new++) = *str; means take the pointer to the string new and dereference it so that we can use it to store where in memeory it points. Then take the value that is pointed to by str and dereference it to the char it points at. Assign that char to where new is and then move the new pointer along to the next spot. Finally, always move the str pointer along with str++ if ithe value is a space or not.
May be it would be clearer to you if were wrote this way:
void r(char *str)
{
char *new = str;
int newStringIndex = 0;
for(int i=0; str[i] != '\0'; i++)
{
if (str[i] != ' ')
{
new[newStringIndex++] = str[i];
}
}
new[newStringIndex] = '\0';
}
Same code functionality, but using a for loop and array indexing instead of pointer math.
the function is removing spaces (in-place) - it copies everything but spaces to the same string as before.
so the if statement is saying: "if the character in str is not a space, then copy it to new" (which is in the same memory area as str, but will start to trail behind when str meets a space).
note how str is always incremented, but new is only incremented when a character is copied. so str scans the whole string, but the data are copied to earlier in the string because new doesn't update when there's a space.
then finally a terminating null is added at new so that the shortened version terminates correctly.
This version of the program (K&R style!) is shorter and does the same:
void r(char *str)
{
char *new;
for (new=str; *new = *str++; ) {
if (*new != ' ') new++;
}
}
while (*str != '\0') {
if (*str != ' ') *(new++) = *str;
str++;
}
is equivalent to:
while (*str != '\0') {
if (*str != ' ') {
*new = *str;
new++;
}
str++;
}
Related
Hi I have a string that was initialized as:
char *line = malloc(100);
Then I used the fgets function to read a line from a file into line
From there i made another string that was initialized as
char *word = malloc(100);
My goal is to read the first word of line character by character and insert those characters into word, up until there is a space in line.
This is what I have tried.
while(*line != 32){
*line = *word;
line++;
word++;
}
*word = '\0';
printf("%s\n", word);
For some reason when I print the value of word afterwards, only blank spaces are being printed. Meaning that I was unsuccessful. However, I can print *line character by character and have the expected value. Why?
For starters you are changing the value of line instead of word. Just a quick eye test shows me you should probably update your code to *word = *line;
In your code, you're modifying both line and word. When you do word++ you are moving the pointer one character forward, so in the end what you end up doing is only printing the last character of word, which is \0 as you just assigned it.
To do this correctly the simplest way is to use auxiliary variables:
char *l, *w;
l = line;
w = word;
while(*l != ' ' && *l != '\0') {
*w = *l;
l++;
w++;
}
*w = '\0';
printf("%s\n", word);
The added check for *l != '\0' is to make sure you don't read past the end of line in case there no space character is found.
Another option would be to use an auxiliary index variable accessing the two strings like arrays, instead of using other pointers:
size_t i;
for (i = 0; line[i] != ' ' && line[i] != '\0'; i++) {
word[i] = line[i];
}
word[i] = '\0';
printf("%s\n", word);
This code finds the next word in the string.
For example
given an input of " my cake" the function should return "my cake". as the expected output
If I use return then the output is (null), but I use printf then the code works
I would like to know how to get the expected output using return.
#include <stdio.h>
int main()
{
char* str[1000];
printf("enter:");
fgets(str,1000,stdin);
printf("%s",find_word_start(str));
}
char* find_word_start(char* str){
char* result[1000];
int c = 0, d = 0;
while(str[c] ==' ') {
c++;
}
while(str[c] != '\0'){
result[d++] = str[c++];
if(str[c]==' ') {
result[d++] = str[c++];
}
while(str[c]==' ') { //
c++;
}
}
result[d] = '\0';
//print or return char?
return result;
}
char* result[1000]; creates an array of 1000 pointers. That's wrong in a number of ways.
You want a block of 1000 chars, not pointers.
Actually, 1000 is not the number of characters you want. You usually want a smaller number, but you could also want a larger number.
You don't want to store the result in automatically allocated memory, because that will be freed as soon as you exit the function. Use malloc (or something that does a malloc such as strdup).
Fix:
// Returns a copy that needs to be freed.
char* find_word_start(const char* src) {
while (*src == ' ')
++src;
size_t len = 0;
while (str[len] != '\0')
++len;
++len; // Include NUL
result = malloc(len);
char* dst = result;
while (len--)
*(dst++) = *(src++);
return result;
}
Well, I was avoiding using string functions above like you did, but they greatly simplify the solution.
// Returns a copy that needs to be freed.
char* find_word_start(const char* src) {
while (*src == ' ')
++src;
return strdup(src);
}
That said, since you return the tail end of the string, you could simply return a pointer into the existing string.
// Returns a pointer into the provided string.
const char* find_word_start(const char* str) {
while (*str == ' ')
++str;
return str;
}
The following line allocates memory space in the stack but after the function ends everything is gone:
char result[1000];
You need to allocate memory in the heap like that:
char *result = malloc(sizeof(char) *1000);
Note: don't forget to free that memory space by free function.
How can we replace spaces in a string using pointers? I tried but unable to get it.
While replacing space with hyphen, the control is coming out of the loop without tracing further.
while (*str != '\0')
{
if (*str == ' ')
*str = '-';
str++;
}
print(str);
Pointers are special type of variables used to store address of other variables. when you changed value inside the str pointer with "str++", it then pointed to the next element and after the while loop str pointed to the last element of the string('\0'). So you must store the the address of the first character of the string to do something with it later.
int main() {
char *s = "abcde", *str =s; // s,str stores address of first character
while(*str!='\0'){
if(*str ==' ')
*str='-';
printf("%c", *str);
str= str+1; // str now points to the next character. But s remains unchanged
}
}
When you use pointers to do this and increment pointers then print(str) will show you end of str so \0.
You must store pointer to begin of str:
char* str = (char*) malloc(sizeof(char) * 255);
memcpy(str, "abc de", 255);
char* beginStr = str;
while(*str!='\0') {
if (*str == ' ') {
*str = '-';
}
str++;
}
printf("%s\n", beginStr);
free(beginStr);
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);
}
In the code below that reverses a string, I don't understand what is the purpose of the if statement. What case is this if statement trying to catch for?
Isn't this superfluous since you've already set char*end= str, and so the statement if(str) has to be true or your code would have already failed by this point?
void reverse(char* str)
{
char *end = str;
char temp;
if (str)
{
while (*end)
{
end++;
}
}
end--; //pulls back one for \0 character
while (str < end)
{
temp = *str;
*str++ = *end;
*end-- = temp;
}
}
It prevents dereferencing a NULL pointer, very good practice.
In case str == NULL, then *end will be undefined behavior, so checking that before dereferencing, is really a good thing to do, because ignoring such possibility will cause a bug that will be very hard to detect, except of course using a debugger, but still, why leave the need to track the problem, when you can avoid it at the expense of almost nothing, generally.
It would actually be better to do something like this
if (str == NULL)
return;
Isn't this superfluous since you've already set char*end= str, and so
the statement if(str) has to be true or your code would have already
failed by this point?
Actually, the line
char *end = str;
will not cause the "code to fail", even if a null pointer was passed as an argument. Then it would just assign NULL to end.
What case is this if statement trying to catch for?
Since we do not know if we were passed a NULL pointer yet, we should check before dereferencing it. That is what the if statement is for.
This code would work correctly:
void reverse(char* str)
{
if (str != NULL)
{
char *end = str;
while (*end != '\0')
end++;
end--; //pulls back one for \0 character
while (str < end)
{
char temp = *str;
*str++ = *end;
*end-- = temp;
}
}
}
This code would also work:
void reverse(char* str)
{
if (str == NULL)
return;
char *end = str; // Assumes C99 or later
while (*end != '\0')
end++;
end--; //pulls back one for \0 character
while (str < end)
{
char temp = *str;
*str++ = *end;
*end-- = temp;
}
}
Both ensure that you never mess with a null pointer. Decrementing a null pointer as in the original code would lead to catastrophe (or, at least, undefined behaviour). Don't risk it.
You can also use strlen() — carefully ensuring you don't run into problems with an empty string:
void reverse(char* str)
{
if (str == NULL || *str == '\0')
return;
char *end = str + strlen(str) - 1;
while (str < end)
{
char temp = *str;
*str++ = *end;
*end-- = temp;
}
}