How does this loop end? - c

code example like this:
#include<stdio.h>
void main()
{
char *s={"abcd"};
do {
printf("%d\n",++s);
} while(*s);
}
Where does the pointer s point when the loop do ends?How does it work?

In C, zero is equivalent to false. So when *s points to the terminator character in the string (a zero), the loop stops.

"abcd" is stored in memory in 5 consecutive bytes: 'a' 'b' 'c' 'd' '\0'.
The last byte, zero, terminates the loop since zero is false in C.

First of all, you should not use %d for formatting a pointer, it is for integers, not for pointers. Use %p instead.
This line-
char *s={"abcd"};
initializes the string with '\0' as the last character.
Your programs loops through each character (from 2nd to last) of the string an prints the address of where they are stored in the memory. Since it is a do-while loop, the condition checking is done after the execution of the body of the loop.
NOTE: It does NOT print the address of the first character because-
printf("%d\n",++s);
this line (due to prefix increment) increments the pointer to the next character before passing its value to printf. So when the body of the loop is executed for the first time, the address of the second character(b) is printed.
Now the condition part of the loop checks whether character at pointed by s (the character can be referred to by *s) is non-zero.
As the string has '\0' as the last character (which has an integer value of 0), the loop terminates when it reaches the last character.
The output of your program (with %d changed to %p) will be something like but NOT exactly same as-
0x40061d
0x40061e
0x40061f
0x400620
Note that only 4 addresses are printed (from 'b' to '\0', the address of 'a' is not printed). To do that you should try this-
#include<stdio.h>
main()
{
char *s={"abcd"};
do {
printf("%p\n",s++);
} while(*s);
printf("%p\n", s); // to print the address of the '\0' character.
}

Related

C - Printing null character using %c in nested printf statement

Why both inner printf() functions are working different even the printing value is same for both functions ?
Here is the code -:
#include<stdio.h>
int main()
{
char ch = '\0';
printf("%d",printf("%c", ch)) ;
// This line will print 1.
printf("%d",printf("\0")) ;
// This line will print 0.
return 0;
}
printf("%d", printf("%c", '\0'));
Why this line prints 1?
The value '\0' is one single character, which "%c" sends th stdout (though you can't see it).
printf("%d", printf("%s", "\0"));
Why this line prints 0?
The string "\0" has two characters in it: the literal '\0' and the implied '\0'. None of them are printed with "%s", the first zero terminates the string. The string "foo" has 4 characters: the 3 literal ones and the implied '\0'
Referring to man page of printf
man 3 printf
printf returns the following
RETURN VALUE
Upon successful return, these functions return the number of characters printed (excluding the null byte used to end output to strings).
So it does not return the count of null bytes.
In the first printf you are explicitly telling to print 1 character, so the output is 1. In the second printf there is nothing to print or NULL. So the output is 0
#include<stdio.h>
int main()
{
char ch = '\0';
printf("%d",printf("%c", ch)) ;
The inner call to printf() prints a null character (you don't see it) and returns 1 as the number of characters printed, which is then printed as the string 1 (you get a null plus a digit 1).
// This line will print 1.
printf("%d",printf("\0")) ;
In this case, you supply a string literal ended in two consecutive null chars, which results on printing an empty string (literally "") and that results in passing to the second printf a 0 and the second printf prints it as the string 0.
// This line will print 0.
return 0;
}
So, you are wrong, in the first case you got a null character printed (a true \0 befpre tje 1. But a null is ignored by the terminal you are using and it doesn't show in your screen, while the second doesn't print anything·)
NOTE
Every C language string related function, explores the string to know how long it is, or when to stop the task it is doing. Putting more than the default string literal's last null char \0 does nothing but shorten the useful part of the string literal. If you try to print "Se está quemando la serrería\0... Duduap!!" or operate on it with any of the string related functions, you'll get the same result as if you had stopped before the first \0 character. So the string literal above is basically equivalent to just "Se está quemando la serrería"
They are working different because first inner printf is printing a character and that character is a null character which has length of 1. While in your second inner printf you are trying to print a string which only contains null character, but due to null character the string became empty with length 0. This is the reason why your first outer printf printed 1 and second outer printf printed 0.

How does a char pointer differ from an int pointer in the below code?

1)
int main()
{
int *j,i=0;
int A[5]={0,1,2,3,4};
int B[3]={6,7,8};
int *s1=A,*s2=B;
while(*s1++ = *s2++)
{
for(i=0; i<5; i++)
printf("%d ", A[i]);
}
}
2)
int main()
{
char str1[] = "India";
char str2[] = "BIX";
char *s1 = str1, *s2=str2;
while(*s1++ = *s2++)
printf("%s ", str1);
}
The second code works fine whereas the first code results in some error(maybe segmentation fault). But how is the pointer variable s2 in program 2 working fine (i.e till the end of the string) but not in program 1, where its running infinitely....
Also, in the second program, won't the s2 variable get incremented beyond the length of the array?
The thing with strings in C is that they have a special character that marks the end of the string. It's the '\0' character. This special character has the value zero.
In the second program the arrays you have include the terminator character, and since it is zero it is treated as "false" when used in a boolean expression (like the condition in your while loop). That means your loop in the second program will copy characters up to and including the terminator character, but since that is "false" the loop will then end.
In the first program there is no such terminator, and the loop will continue and go out of bounds until it just randomly happen to find a zero in the memory you're copying from. This leads to undefined behavior which is a common cause of crashes.
So the difference isn't in how pointers are handled, but in the data. If you add a zero at the end of the source array in the first program (B) then it will also work well.
In str2, You have assigned String. Which means there will be end Of
String('\0' or NULL) due to which when you will increment Str2 and it will
reach to end of string, It will return null and hence your loop will break.
And with integer pointer, there is no end of string. thats why its going to infinite loop.
Joachim gave a good explanation about String terminal character \0 in C language.
Another thing to be aware of when working with pointer is pointer arithmetic.
Arithmetic unit for pointer is the size of the entity pointed.
With a char * pointer named charPtr, on system where char are stored on 1 byte, doing charPtr++ will increase the value in charPtr by *1 (1 byte) to make it ready to point to the next char in memory.
With a int * pointer named intPtr, on system where int are stored on 4 bytes, doing intPtr++ will increase the value in intPtr by 4 (4 bytes) to make it ready to point to the next int in memory.

Does a C for-loop exit on encountering a '\0' character?

I was going through a hash function and encountered a condition where the for loop is supposed to exit when a '\0' (NIL) character comes.
unsigned int hash_string (const char *s)
{
register unsigned int i;
for (i = 0; *s; s++) { // This for loop is supposed to end
// when a '\0' comes?
i *= 16777619;
i ^= *s;
}
return i;
}
As far as I know a C-Loop is supposed to end if a condition returns 0.
Here, however, there is no such condition and it still works?
Could someone also tell on what all conditions does a loop succed/fail?
The null character has the value of 0, so in your example, *s will evaluate to zero if it corresponds to the null termination of the character string.
From 5.2.1 Character sets
... A byte with all bits set to 0, called the null character, shall
exist in the basic execution character set; it is used to terminate a
character string.
Then in 6.4.4.4 Character constants
12 EXAMPLE 1 The construction '\0' is commonly used to represent the
null character.
*s de-references the character pointed by s.
If the character code is 0 the loop breaks and it passes for all values other than 0.
\0 is guaranteed to be 0, that why it is guaranteed that loop will terminate at string end when it encounters NUL character.
One of the reason for choosing \0 as string termination in C is to make constructs like this possible.
When *s evaluates to 0 or false, which is convertable from one another, the loop ends.
In fact, the integer representation for character \0 is 0. So it's the same thing.

printing int array as string

I am trying to print int array with %s. But it is not working. Any ideas why?
#include<stdio.h>
main() {
int a[8];
a[0]='a';
a[1]='r';
a[2]='i';
a[3]='g';
a[4]='a';
a[5]='t';
a[6]='o';
a[7] = '\0';
printf("%s", a);
}
It prints just a.
I tried with short as well, but it also does not work.
This is because you are trying to print a int array, where each element has a size of 4 byte (4 chars, on 32bit machines at least). printf() interprets it as char array so the first element looks like:
'a' \0 \0 \0
to printf(). As printf() stops at the first \0 it finds, it only prints the 'a'.
Use a char array instead.
Think about the way integers are represented - use a debugger if you must. Looking at the memory you will see plenty of 0 bytes, and %s stops when it reaches a 0 byte.
It prints just a.
That's why it prints just a. Afterwards it encounters a 0 byte and it stops.
Because you declared a as an integer, so those signle characters you initialized would result in an error. You must change it to a char variable. However to save time, just make the variable a pointer using the asterisk character, which then allows you to make a single string using double quotes.
int a[8] means array of 8 ints or 8*(4 bytes) - Say 32 bit architecture
a[0] = 'a' stores in the first int index as 'a''\0''\0''\0'
a[1] = 'r' as 'r''\0''\0''\0' and so on . . .
%s represents any C-style string ie. any string followed by a '\0' character
So
printf("%s", a);
searches for trailing '\0' character and just prints "a" assuming it is the entire string

Don't understand how this for loop works

Can someone explain how this loop works? The entire function serves to figure out where in hash to place certain strings and the code is as follows:
//determine string location in hash
int hash(char* str)
{
int size = 100;
int sum;
for(; *str; str++)
sum += *str;
return sum % size;
}
It seems to iterate over the string character by character until it hits null, however why does simple *str works as a condition? Why does str++ moves to the next character, shouldn't it be something like this instead: *(str+i) where i increments with each loop and moves "i" places in memory based on *str address?
In C, chars and integers implicitly convert to booleans as: 0 - false, non-zero - true;
So for(; *str; str++) iterates until *str is zero. (or nul)
str is a pointer to an array of chars. str++ increments this pointer to point to the next element in the array and therefore the next character in the string.
So instead of indexing by index. You are moving the pointer.
The condition in a for loop is an expression that is tested for a zero value. The NUL character at the end of str is zero.
The more explicit form of this condition is of course *str != '\0', but that's equivalent since != produces zero when *str is equal to '\0'.
As for why str++ moves to the next character: that's how ++ is defined on pointers. When you increment a char*, you point it to the next char-sized cell in memory. Your *(str + i) solution would also work, it just takes more typing (even though it can be abbreviated str[i]).
This for loop makes use of pointer arithmetic. With that you can increment/decrement the pointer or add/substract an offset to it to navigate to certain entries in the array, since array are continuous blocks of memory you can do that.
str points to a string. Strings in C always end with a terminating \0.
*str dereferences the actual pointer to get the char value.
The for loop's break condition is equivalent to:
*str != '\0'
and
str++
moves the pointer forward to next element.
The hole for-loop is equivalent to:
int len = strlen(str);
int i;
for(i = 0; i < len; i++)
sum += str[i];
You could also write is as while-loop:
while(*str)
sum += *str++;
Why does str++ moves to the next character, shouldn't it be something like this
instead: *(str+i) where i increments with each loop and moves "i" places in
memory based on *str address?
In C/C++, string is a pointer variable that contains the address of your string literal.Initially Str points to the first character.*(str) returns the first character of string.
Str++ points to second charactes.Thus *(str) returns the second character of the string.
why does simple *str works as a condition?
Every c/c++ string contains null character.These Null Characters signify the end of a character string in C. ASCII code of NUL character is 0.
In C/C++,0 means FALSE.Thus, NUL Character in Conditional statement
means FALSE Condition.
for(;0;)/*0 in conditions means false, hence the loop terminates
when pointer points to Null Character.
{
}
It has to do with how C converts values to "True" and "False". In C, 0 is "False" and anything else is "True"
Since null (the character) happens to also be zero it evaluates to "False". If the character set were defined differently and the null character had a value of "11" then the above loop wouldn't work!
As for the 2nd half of the question, a pointer points to a "location" in memory. Incrementing that pointer makes it point to the next "location" in memory. The type of the pointer is relevant here too because the "Next" location depends on how big the thing being pointed to is
When the pointer points to a null character it is regarded as false. This happens in pointers. I don't know who defined it, but it happens.
It may be just becuase C treats 0 as false and every other things as true.
For example in the following code.
if(0) {
puts("true");
} else {
puts("false");
}
false will be the output
The unary * operator is a dereference operator -- *str means "the value pointed to by str." str is a pointer, so incrementing it with str++ (or ++str) changes the pointer to point to the next character. So it is the correct way to increment in the for loop.
Any integral value can be treated as a Boolean. *str as the condition of the for loop takes the value pointed to by str and determine if it is non-zero. If so, the loop continues Once it hits a null character, it terminates.

Resources