How are these characters produced? - c

int main(void)
{
char s[] = "Hsjodi", *p;
for(p = s; *p; p++)
--*p;
puts(s);
return 0;
}
The output writes Grinch but I cant understand how this code executes. How can it write out Grinch when such letters G,r,i for example does not exist in the char array and when does loop terminates our exactly does *p means?

First of all, notice that for loop does not have any braces to create a block, so the loop body is only
--*p;
which is same as
--(*p);
Now, as per the above statement all the elements in the array, until the terminating null, has been reduced one place. That means, H is now G, s is now r and so on.NOTE
Also, the condition check in the loop *p is a short-hand form of writing *p != '\0' or *p != 0.
After the decrement through the loop, the modified array has been printed through puts().
NOTE: You may want to check the ASCII table for reference.

Related

Error in very similar functions while manipulating strings in C

I am learning C and I came across a problem while manipulating strings.
In a problem I was solving I was supposed to write a function to take a string and a character and delete all occurrences of the given character, and then I had to return the modified string.
The function I wrote is this:
char *strdelc3(char *s, char ch){
for(int i=0,j=0; i!=strlen(s)+1; ++i)
if(s[i]!=ch){
s[j]=s[i];
++j;
}
return s;
}
And when I pass a string and a character as arguments:
main(){
char s[20]="mary";
puts(strdelc3(s,'r'));
}
The output is: Segmentation fault(core dumped),
which by my research means I am accessing memory that does not belong to me.
The solutions had this code:
char *strdelc4(char *s, char ch){ /*Correct*/
int i,j;
for(i=0, j=0; s[i]!='\0'; ++i)
if(s[i]!=ch){
s[j]=s[i];
++j;
}
s[j]='\0';
return s;
}
Which is basically equal to mine, however this piece works fine!
Since the two codes are so similar I don't see anything wrong with mine...
I have already studied both but I don't see what is the problem with mine... Could someone help?
The problem is in your loop conditional:
i!=strlen(s)+1
You're attempting to use strlen(s)+1 here to avoid having to add the null byte. But in doing so, strlen(s) changes once you move the terminating null byte.
On the first 4 iterations through the loop, strlen(s) is 4. On the next iteration, i is 4 and strlen(s)+1 is 5 so you enter the loop again. You then move the null byte. Now on the following iteration, strlen(s) is 3 and i is 5. The conditional is still true so you keep going, walking off the end of the string. This invokes undefined behavior which in this case causes a crash.
The second piece of code addresses this issue by explicitly looking for the null byte based on the index of i and appending a null byte to the resulting string after the loop.
An even simpler version of the code would use the do - while loop instead of for():
char *strdelc5idx(char *s, char ch){
int i=0, j=0;
do {
if (s[i] != ch)
s[j++] = s[i];
} while (s[i++] != 0);
return s;
}
This will copy the string-terminating NUL character before testing it, so you needn't have a separate instruction for it. However, that requires deferring the i++ incrementation so that the loop condition at the end of an iteration tests the same character which was copied in the iteration. As a result the i++ and j++ do no longer appear together, which may make this code less legible at a first glance.
An equivalent pointer version:
char *strdelc5ptr(char *s, char ch){
char *d = s, *f = s;
do {
if (*f != ch)
*d++ = *f;
} while (*f++);
return s;
}

Iterate through an array of characters in C

Recently I saw this while loop condition in C in the example below but I have no idea what the while condition really means and how the compiler knows when it is done. Could someone explain it to me?
This is what I believe it means: while loop iterates through the char array until the ending of the array since there is nothing else then the while loop ends, or am I wrong? I tried to use the same while loop but in another language such as Go, however, the compiler threw an error saying that I cannot use a non-bool.
// C program to demonstrate
// example of tolower() function.
#include <ctype.h>
#include <stdio.h>
int main()
{
int j = 0;
char str[] = "GEEKSFORGEEKS\n";
// Character to be converted to lowercase
char ch = 'G';
// convert ch to lowercase using toLower()
char ch;
while (str[j]) { // <- this part, how is this a condition?
ch = str[j];
// convert ch to lowercase using toLower()
putchar(tolower(ch));
j++;
}
return 0;
}
the while loop can be understood as "while this string has characters" and as known in C strings or an array of chars contain a '\0' => Null character, in the end, once the while loop achieves it, it will stop the iteration.
So yeap! you are right.
You can think of an array of chars as following:
So as you see in the picture an array of chars is already a pointer, and each of the characters has an address, as well that the address of a pointer is the address of the first element, so when you declared
char str[] = "GEEKSFORGEEKS\n";
it was allocated in the memory like below:
[G][E][E][K][S][F][O][R][G][E][E][K][S][\n][\0]
The program will crash because you have a redeclaration of ch variable, as well there is no need to initialize the char ch = 'G'; since you're overriding it in the while loop and it will take str[j], and so you started iterating at j = 0 which the 1st index in the array [G], as you're incrementing the loop will go until the null character [\0] and stop because there's no iteration after the NULL, in other examples you might see the following condition in the loop: while(str[j] != '\0') which is similar to your condition but just more specific.
You can gain more performance by iterating through the pointer just like the following:
#include <ctype.h>
#include <stdio.h>
int main()
{
char *str = "GEEKSFORGEEKS\n";
while (*str)
putchar(tolower(*str++));
return 0;
}
Although, you got your answer. Still, I wanna add some more details or an explanatory answer here.
In C, a conditional statement will have either the value 1 or 0. In the end, they all are evaluated to Boolean values true or false or 1 or 0.
So first, try to understand or dry run that while(str[j]). Guess what will be the value of str[j] when j = 0. It'll be the first character "G". Similarly in the next iteration, you'll get the next character until NULL character or String Termination character. Now, anything in between those parentheses in while(str[j]) will be considered as a conditional statement and they all are evaluated to 1 or 0. Now here's the thing that anyhow if that conditional statement isn't being evaluated specifically to 0, then It'll be supposed to have the value of 1.
So, here str[j] when j = 0 will be evaluated as 1, then next character and so on. Now, when we find \0 which is an escape character equivalent to 0. So, at \0 while loop will terminate as the condition will be false.
Can, you tell me what will be the output of this program?
#include<stdio.h>
int main()
{
if(printf("Hello TraineeGuy\n"))
printf("TRUE");
else
printf("FALSE");
return 0;
}

while(*p++) loop doesn't print the first element of the string

I have a stored a string in a pointer variable which has memory in heap section. When I print the string character by character the first element is skipped.
Example: if char *p="hello" when i print character by character using while(*p++) loop 'h' is skipped and output is "ello" please can any one explain it?
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *p=(char*)malloc(sizeof(char)*20);
printf("enter string\n");
scanf("%s",p);
while(*p++)// value is assign and address is increased
{
printf("%c",*p);//why first character is skipped??
}
return 0;
}
To see the first letter, change *p to p[-1], because p++ has already incremented p, so by the time you first use *p, p already points to the 2nd letter (with index 1).
There are many other ways to solve it, e.g.
for (; *p; ++p) {
putchar(*p);
}
Because while(*p++) increments the value as soon as the loop starts. By the time the printf statement is reached, p has already been incremented.
p = 0
while(p++) { // p = p + 1
printf('%d', p); // p = 1 when this executes
}
while(*p++) after this statement p is incremented and moved ahead. So at printf() p already points to 2nd character.
The line while(*p++) will check the value of *p and then increment p, before entering the body of the loop. You can improve the code by using a for loop
for ( ; *p; p++ )
printf( "%c", *p );
or by incrementing the pointer after using it, in the body of the loop
while(*p)
printf( "%c", *p++ );

Can someone explain this C code? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
Can someone explain this reverse sentence code for me? How does the first and the second looping works? What's the point of each of them?
main(){
char arr[255], *p;
printf("Enter string: ");
gets(arr);
for(p=arr; *p!='\0'; p++);
for(p--; p>=arr; p--){
printf("%c",*p);
}
}
Input:
I love you
Output:
uoy evol I
The code is basically printing in reverse the input array.
for(p=arr; *p!='\0'; p++);
Sets p as the last (relevant) element of the array (the null character)
for(p--; p>=arr; p--){
printf("%c",*p);
}
starts from the last (none null) character and prints each one from last to first.
Question for you:
What happens if the input array is longet than 255 chars? (answer below)
buffer overflow
Suppose the input is Hello World. This gets stored in your buffer arr as
[H][e][l][l][o][ ][W][o][r][l][d][\0]...
Your pointer is set to arr, hence the pointer points to H
[H][e][l][l][o][ ][W][o][r][l][d][\0]...
^
|
p
The first loop advances (p++) until it meets the first null character (\0). It now looks like
[H][e][l][l][o][ ][W][o][r][l][d][\0]...
^
|
p
Now the second loop goes back (p--) until it reaches the first character again (actually, until the pointer equals the pointer to the beginning of the array), printing each character as it meets it. The first character \0 however is ignored with the little p-- here:
for(p--; p>=arr; p--)
^^^
The code looks clever, but it actually exhibits undefined behavior, which means the code may do anything.
The problem is the second loop:
for(p--; p>=arr; p--){
printf("%c",*p);
}
What it's intended to do is to start p at the last character of the string (excluding the terminating \0, then keep decrementing it until all the characters of the string have been output in reverse order.
The problem is the termination condition: after the intended end of the loop, p is arr, and then p-- subtracts one, and then p >= arr is false.
Unfortunately, an arithmetic operation on pointers may not result in a pointer that no longer points to the object (or one after the final object of an array), or it's undefined behavior.
That's what's happening here: p-- causes p to be off the array, and all bets are off as to what happens next.
Here's a correct way to write the second loop:
for (int i = (p-arr)-1; i >= 0; i--) {
printf("%c", p[i]);
}
I'd probably write the entire code using indexes to completely avoid pointer arithmetic. Maybe something like this:
int i = 0;
// Find the terminating \0 byte
while(p[i])i++;
// Iterate backwards through the string, outputting characters along the way.
while(--i >= 0)putc(p[i]);
Before explaining the code, I must say two things - first, the signature of the main function should be one of the following -
int main(void);
int main(int argc, char *argv[]);
and second, do not use gets. It's not safe to use. Use fgets instead. Now, coming to the code.
for(p = arr; *p != '\0'; p++) ;
In the above loop, p is assigned the base address of the array arr, i.e., the address of the first element of the array arr. The array arr contains a terminating null byte which means it is a string. The loop body is the null statement ; which means p is incremented till the null byte is encountered, i.e., when the test *p != '\0' fails. In the for loop
for(p--; p >= arr; p--) {
printf("%c",*p);
}
p is first decremented to point to the last character just before the null byte and then it is printed in each iteration till the condition p >= arr is true, i.e., till the first element of the array is reached. You should change your code to -
#include <stdio.h>
int main(void) {
char arr[255], *p;
printf("Enter string:\n");
fgets(arr, sizeof arr, stdin);
for(p = arr; *p! = '\0'; p++)
; // the null statement
for(p--; p >= arr; p--)
printf("%c", *p);
return 0;
}

Unexpected C code output

This is my c code:
#include <stdio.h>
int main(){
int x[] = {6,1,2,3,4,5};
int *p=0;
p =&x[0];
while(*p!='\0'){
printf("%d",*p);
p++;
}
return 0;
}
When run the output is 612345-448304448336
What are the digits after the minus sign and why is my code giving this?
The condition *p != '\0', which is the same as *p != 0, is never met because your array doesn't contain an element of value 0, and thus you overrun the array bounds and step into undefined behaviour.
Instead, you should control the array range directly:
for (int const * p = x; p != x + sizeof(x)/sizeof(x[0]); ++p) // or "p != x + 6"
{
printf("%d", *p);
}
You run the loop till you encounter a \0 but your array was never \0 terminated.
int x[] = {6,1,2,3,4,5};
creates an array which is not \0 terminated. You will have to explicitly add a \0 as the last element.
Since the array is not \0 terminated the while() loops run until a random \0 is encountered. Technically, this is Undefined Behavior because you are reading the contents of memory which is not allocated to your variable.
Suggested Solution:
int x[] = {6,1,2,3,4,5,0};
while(*p != 0)
Arrays in C are not Null Terminated. Which is why your loop goes beyond the end of your declared array. The digits follows 5 are just whatever happens to be in that memory space. If there hadn't been a null character following your allocation of the array the loop would have continued running until it made a SegFault.

Resources