how the following for loop function differently - c

#include<stdio.h>
void main()
{
int a,b,c;
for(b = c = 10; a = "- FIGURE?, UMKC,XYZHello Folks,TFy!QJu ROo TNn(ROo)SLq SLq ULo+UHs UJq TNn*RPn/QPbEWS_JSWQAIJO^NBELPeHBFHT}TnALVlBLOFAkHFOuFETpHCStHAUFAgcEAelclcn^r^r\\tZvYxXyT|S~Pn SPm SOn TNn ULo0ULo#ULo-WHq!WFs XDt!"[b+++21];)
{
for(;a-->64;)
{
putchar((++c == 'Z') ? (c = c/9) : (33^b&1));
}
}
getch();
}
Above program in c language gives the output as map of India. In the above program outer for loop has 2 slots and the third one is left empty. However I understood how the program works but the doubt is that the condition slot of the outer for loop works as an assignment slot. Syntactically and logically this should be wrong but it works. According to the value in array index, ASCII code of corresponding char is assigned variable a.
How this works?

The condition slot of the outer for loop assigns to a one of the characters of the string literal, at the same time incrementing b. Because the assignment operator also returns the assigned value, the condition of the outer for loop becomes the value of some of the characters of the string literal. Because strings are '\0'-delimited in C, the condition is true until the expression b++ + 21 reaches the end of string (then the last (extra) character of the string is returned, and it's equal to 0, thus evaluating as false)
In fact, this is an obfuscated and more complex version of a common C idiom for iterating a string, which looks like this:
char *string = "my string";
int i;
for (i = 0; string[i]; ++i)
/* do something with string[i] */
which can be simplified to:
int i = 0;
for (; string[i++]; )
/* do something with string[i] */
Moreover, the current character can be extracted to a separate char variable c:
int i = 0;
char c;
for (; c = string[i++]; )
/* do something with c */
A while loop can be used instead as well:
while (c = string[i++])
/* do something with c */

Related

Can't understand small part of strcmp function

I'm reading a book in C and have seen these two strcmp algorithm.
I have learned my self how the usel for loop works.
But these two for loop are new for me. I don't understand these parts
for (i = 0; s[i] == t[i]; i++)
It have no length instead have this s[i] == t[i].
for ( ; *s == *t; s++, t++) what means this guy ;.
The other parts i understand and I'm also aware what these function returns.
/* strcmp: return <0 if s<t, 0 if s==t, >0 if s>t */
int strcmp(char *s, char *t)
{
int i;
for (i = 0; s[i] == t[i]; i++)
if (s[i] == '\0')
return 0;
return s[i] - t[i];
}
int strcmp(char *s, char *t)
{
for ( ; *s == *t; s++, t++)
if (*s == '\0')
return 0;
return *s - *t;
}
First, some basics.
The syntax of a for loop is
for ( expr1opt ; expr2opt ; expr3opt ) statement
Each of expr1, expr2, and expr3 are optional. The statement
for ( ; ; ) { // do something }
will loop "forever", unless there's a break or return statement somewhere in the body of the loop.
expr1, if present, is evaluated exactly once before loop execution - it's used to establish some initial state (such as setting an index to 0, or assigning a pointer value, or something like that).
expr2, if present, is evaluated before each iteration of the loop body. It's the test condition for continuing loop execution. If the expression evaluates to a non-zero value, the loop body is executed; otherwise, the loop exits. If expr2 is missing, it is assumed to evaluate to 1 (true).
expr3, if present, is evaluated after each iteration of the loop body. It usually updates whatever is being tested in expr2.
for (i = 0; s[i] == t[i]; i++) It have no length instead have this s[i] == t[i]
This loop will execute as long as s[i] == t[i]; as soon as t[i] is not equal to s[i], the loop will exit. By itself, this means the loop will run past the end of the string in case you have identical strings - if both s and t contain "foo", then the loop will run as
s[0] == t[0] == 'f'
s[1] == t[1] == 'o'
s[2] == t[2] == 'o'
s[3] == t[3] == 0
s[4] == t[4] // danger, past the end of the string
So, within the body of the loop, the code also checks to see if a[i] is 0 - if so, that means we've matched everything up to the 0 terminator, and the strings are identical.
So, basically, it goes...
s[0] == t[0] == 'f', s[0] != 0, keep going
s[1] == t[1] == 'o', s[1] != 0, keep going
s[2] == t[2] == 'o', s[2] != 0, keep going
s[3] == t[3] == 0, s[3] == 0, at end of s, strings match
for ( ; *s == *t; s++, t++)
does exactly the same thing as the first loop, but instead of using the [] operator to index into s and t, it just uses the pointers. Since there's nothing to initialize, the first expression is just left empty.
In the first case, the code after the for statement is checking to see if the end-of-string marker has been found, and if so the function returns 0.
In the case of the second for statement, the initialization part of the for statement is not filled in, so the statement starts with for( ;. This is perfectly legitimate.
Best of luck.
For loop has 3 parts - initialization , condition and loop expresion. All these are optional.
So this loop-
for (i = 0; s[i] == t[i]; i++)
It runs till character s[i] is equal to t[i]. So this is condition. If it is false loop breaks.
It is not necessary that condition is always based on length.
And this one -
for ( ; *s == *t; s++, t++)
As we see above intialization is optional and is not present here which is perfectly fine. Condition in this loop is also same i.e loop till characters are equal.
for (i = 0; s[i] == t[i]; i++) // It has no length
Actually this code is slightly dangerous, as it assumes that the passed strings are NULL-terminated (but read later). The cycle goes on only while the left-part of the strings are equal so, inside the loop, the only possible result to be returned is 0 (equal), when a NULL is encountered (the for(;;) condition ensures that the two strings both have the NULL in the same position).
About the length, to calculate it you should scan the whole string anyway... and two times (because there are two strings). This cycle instead combines all in one. Moreover, strings in C must be NULL terminated. Definitely, there is no other way to do this comparison!
for ( ; *s == *t; s++, t++) // what means this guys
This is about the same as the previous, but instead of dereferencing s and t using an index (and without touching them), they are modified to point to the characters, one after another. I believe this is faster, but depends on the compiler. Moreover, incrementing s and t makes you lose the start of the strings; but in this function it is not a problem.
About the syntax of for(;;), a comment already explained why it is written like this. The last part of the for(), between the semicolon and the closing bracket, is executed after every iteration. In this case we need to increment two variables, so there are two statements separated by a comma.
It doesn't have be a length. The for loop is run until the condition is true, so in this case it means it will be running until s[i] is not equal to t[i].
for ( ; *s == *t; s++, t++)
; here means that the first clause of the for loop is omitted. As
bot s and t are defined outside of for loop there is no need to define them here.
It's allowed by the C standard:
for ( clause-1 ; expression-2 ; expression-3 ) statement
(...)
Both clause-1 and expression-3 can be omitted. An omitted expression-2 is
replaced by a nonzero constant.
Some compilers such as clang produce a warning when an already defined variable is put in the first clause. For example this code:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int i = 0;
for (i; i < 10; i++)
puts("Hi");
return EXIT_SUCCESS;
}
compiled with clang produces a warning:
main.c:7:8: warning: expression result unused [-Wunused-value]
for (i; i < 10; i++)
^

The use of tolower and storing in an array

I am trying to trace through this problem and can not figure out how the star is goes through the while loop and is stored in the array. Is * stored as 8 because of tolower? If anyone could please walk through the first for - to second for loop please I would be eternally grateful.
#include <stdio.h>
#include <ctype.h>
int main()
{
int index, freq[26], c, stars, maxfreq;
for(index=0; index<26; index++)
freq[index] = 0;
while ( (c = getchar()) != '7')
{
if (isalpha(c))
freq[tolower(c)-'a']++;
printf("%d", &freq[7]);
}
maxfreq = freq [25];
for (index = 24; index >= 0; index--)
{
if (freq[index] > maxfreq)
maxfreq = freq[index];
}
printf ("a b c d e f\n");
for (index = 0; index < 5; index++)
{
for (stars = 0; stars < (maxfreq - freq[index]); stars ++)
printf(" ");
for (stars = 0; stars < (freq[index]); stars++)
printf("*");
printf("%c \n", ('A' + index) );
printf(" \n");
}
return 0;
}
It seems that this code is a histogram of sorts that prints how many times a given character has been entered into the console before it reaches the character '7'.
The following code:
for(index=0; index<26; index++)
freq[index] = 0;
Is simply setting all of the values of the array to 0. This is because of the fact that in C, variables that are declared in block scope (that is, inside a function) and that are not static do not have a specific default value and as such simply contain the garbage that was in that memory before the variable was declared. This would obviously affect the results that are displayed each time it is run, or when it is run elsewhere, which is not what you want I'm sure.
while ( (c = getchar()) != '7')
{
if (isalpha(c))
freq[tolower(c)-'a']++;
printf("%d", &freq[7]);
}
This next section uses a while loop to continue accepting input using getchar() (which gets the next character of input from STDIN in this case) until the character "7" is reached. This is due to the fact that assigning a value (such as "c = getchar()") allows the value to be used in such a way that it can be compared using "! = '7'". This allows us to continue looping until the character that is accepted from STDIN is equal to '7', after which the while loop will end.
Inside the loop itself, it's checking the value that has been entered using "isalpha()", which returns true if the character is an alphabetic letter. By using "tolower()" and returning that value to be subtracted by the character value of 'a', we are basically finding which character in the alphabet this is numerically. An example would be if we took the letter 'F'. Capital 'F' is stored as the value 70 in the background. tolower() checks to see if it is an uppercase character, and if it is, it returns the lowercase version of it (in this case, 'f' == 102). This value is then subtracted by 'a' (stored as 97) which returns the value 6 (which, when counting from 0, is the position of 'F' in the alphabet). This is then used to target that element of the array and to increment it, which tells us that another "F" or "f" has been entered.
maxfreq = freq [25];
for (index = 24; index >= 0; index--)
{
if (freq[index] > maxfreq)
maxfreq = freq[index];
}
This next section sets the variable "maxfreq" to the last value (how many times 'Z' was found), and iterates downwards, changing the value of maxfreq to the highest value that is found (that is, the largest number of any given character that is found in the array). This is later used to format the output to make sure that the letters line up correctly and the number of stars and spaces are correct.

accessing array of strings in C

How to declare array of strings in C.
Is it like
char str[100][100] ={"this","that","those"};
If so how to access the values .. can i travers like this?
(It does not give any compilation error ..but shows some additional garbage characters)
int i ,j;
char c[100][100] = {"this","that"};
for(i = 0 ;c[i] != '\0';++i)
for(j = 0; c[i][j] != '\0';++j)
printf("%c",c[i][j]);
Is it necessary to add '\0' at end of eac string..for ex:
char c[100][100]={"this\0","that\0"}
How to declare array of strings in C
It is Ok, but you will have to be extremely careful of buffer-overflow when dealing with these strings
can i travers like this?
Note that the condition in the first for loop: for(i = 0 ;c[i] != '\0';++i) is probably wrong, and will fail since c[i] is an array, whose address is not 0. You should probably iterate the outer array by numbers [until you read all elements], and not until you find some specific character. You can do that by maintaining a different variable n, which will indicate how many elements does the array currently have.
Is it necessary to add '\0' at end of eac string..for ex:
No - the compiler add it to you, it is just fine without adding the '\0' to the string.
Yes, you can declare an array of strings that way.
No, you can't traverse it like that, the condition on your outer loop is bad - a string (char *) will never be equal to a character '\0'. The inner loop is fine.
No, you don't need to add the '\0', that will happen automatically.
c[i] is a pointer, so it has nothing to do with '\0'
so instead you should check c[i][0]
The compiler will add '\0' for you when you input a string like "this"
char str[100][100] ={"this","that","those"};
int main()
{
int i ,j;
char c[100][100] = {"this","that"};
for(i = 0 ;c[i][0] != '\0';++i)
{
for(j = 0; c[i][j] != '\0';++j)
printf("%c",c[i][j]);
}
}

Is it ok to iterate backwards to one before the beginning of an array

If for example I have a ptr to a string and move ptr to last character in string and iterate backwards to beginning of string using *p-- and I iterate to position one before start of array is this OK? Or will I get an access violation? I am only moving pointer - not accessing. It seems to work in my code so wondering if it is bad practice or not?
Here is a sample - line with *next-- = rem + 'A'; is one I am questioning if ok???
#include <stdio.h> /* printf */
#include <string.h> /* strlen, strcpy */
#include <stdlib.h> /* malloc/free */
#include <math.h> /* pow */
/* AAAAA (or whatever length) = 0, to ZZZZZ. base 26 numbering system */
static void getNextString(const char* prev, char* next) {
int count = 0;
char tmpch = 0;
int length = strlen(prev);
int i = 0;
while((tmpch = *prev++) != 0) {
count += (tmpch - 'A') * (int)pow(26.0, length - i - 1);
++i;
}
/* assume all strings are uppercase eg AAAAA */
++count;
/*if count above ZZZ... then reset to AAA... */
if( count >= (int)pow(26.0, length))
count = 0;
next += (length-1); /* seek to last char in string */
while(i-- > 0) {
int rem = count % 26;
count /= 26;
*next-- = rem + 'A'; /*pntr positioned on 1 before array on last iteration - is OK? */
}
}
int main(int argc, char* argv[])
{
int buffsize = 5;
char* buff = (char*)malloc(buffsize+1);
strcpy(buff, "AAAAA");
int iterations = 100;
while(--iterations){
getNextString(buff, buff);
printf("iteration: %d buffer: %s\n", iterations, buff);
}
free(buff);
return 0;
}
According to the following C-FAQ question\answer, and I quote:
Pointer arithmetic is defined only as long as the pointer points
within the same allocated block of memory, or to the imaginary
``terminating'' element one past it; otherwise, the behavior is
undefined, even if the pointer is not dereferenced.
So my answer would be no, it is not OK to iterate before the beginning of an array.
There are references to the C standards as well:
K&R2 Sec. 5.3 p. 100, Sec. 5.4 pp. 102-3, Sec. A7.7 pp.
205-6
ISO Sec. 6.3.6 (C89) or 6.5.6/8 (C99)
Rationale Sec. 3.2.2.3
As long as you don't try to read or write from that address, it won't cause a violation. This is becuase the value in a ptr is just another number.
The only reason your code is working is that your length happens to be less than or equal to the initial value in i.
I personally would not want to rely on this, since I know I'd forget about that particular condition, and I'd make some modification that broke it. So while it technically works, it's not really a good idea.
[expr.add], ΒΆ5
If both the pointer operand and the result point to elements of the same array object, or one past
the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is
undefined.
So it's UB, since the result do not point to any valid element of the array.
comment, acctually: (to FelixCQ's answer)
I could understand why obtaining an Out-of-range pointer in a loop could be dangerous because of possible loop unrolling and out-of-order evaluation, so that the pointer could get derefferenced before the terminating condition is evaluated, as in this simple example:
for (char* tmp = s+len; tmp >= s; tmp--) sum += *tmp;
However, if this is the reason for UB, then
for (int i = len; i >= 0; i--) sum += s[i];
has exactly the same problem! Or am I missing something?

Why are the elements in my char* array two bytes instead of four? :

I am new to C, so forgive me if this question is trivial. I am trying to reverse a string, in
my case the letters a,b,c,d. I place the characters in a char* array, and declare a buffer
which will hold the characters in the opposite order, d,c,b,a. I achieve this result using
pointer arithmetic, but to my understanding each element in a char* array is 4 bytes, so when I do the following: buffer[i] = *(char**)letters + 4; I am supposed to be pointing at the
second element in the array. Instead of pointing to the second element, it points to the third. After further examination I figured that if I increment the base pointer by two
each time I would get the desired results. Does this mean that each element in the array
is two bytes instead of 4? Here is the rest of my code:
#include <stdio.h>
int main(void)
{
char *letters[] = {"a","b","c","d"};
char *buffer[4];
int i, add = 6;
for( i = 0 ; i < 4 ; i++ )
{
buffer[i] = *(char**)letters + add;
add -= 2;
}
printf("The alphabet: ");
for(i = 0; i < 4; i++)
{
printf("%s",letters[i]);
}
printf("\n");
printf("The alphabet in reverse: ");
for(i = 0; i < 4; i++)
{
printf("%s",buffer[i]);
}
printf("\n");
}
You're not making an array of characters: you're making an array of character strings -- i.e., an array of pointers to arrays of characters. I am not going to rewrite the whole program for you of course, but I'll start out with two alternative possible correct declarations for your main data structure:
char letters[] = {'a','b','c','d, 0};
char * letters = "abcd";
Either of these declares an array of five characters: a, b, c, d followed by 0, the traditional ending for a character string in C.
Another thing: rather than making assumptions about the size of things, use the language to tell you. For instance:
char *my_array[] = { "foo" , "bar" , "baz" , "bat" , } ;
// the size of an element of my_array
size_t my_array_element_size = sizeof(my_array[0]) ;
size_t alt_element_size = size(*my_array) ; // arrays are pointers under the hood
// the number of elements in my_array
size_t my_array_element_cnt = sizeof(my_array) / sizeof(*myarray ;
// the size of a char
size_t char_size = sizeof(*(my_array[0])) ; // size of a char
Another thing: understand your data structures (as noted above). You talk about chars, but your data structures are talking about strings. Your declarations:
char *letters[] = {"a","b","c","d"};
char *buffer[4];
get parsed as follows:
letters is an array of pointers to char (which happen to be nul-terminated C-style strings), and it's initialized with 4 elements.
Like letters, buffer is an array of 4 pointers to char, but uninitialized.
You are not actually dealing individual chars anywhere, even in the printf() statements: the %s specifier says the argument is a nul-terminated string. Rather, you're dealing with strings (aka pointers to char) and arrays of the same.
An easier way:
#include <stdio.h>
int main(void)
{
char *letters[] = { "a" , "b" , "c" , "d" , } ;
size_t letter_cnt = size(letters)/sizeof(*letters) ;
char *buffer[sizeof(letters)/sizeof(*letters)] ;
for ( int i=0 , j=letter_cnt ; i < letter_cnt ; ++i )
{
buffer[--j] = letters[i] ;
}
printf("The alphabet: ");
for( int i = 0 ; i < letter_cnt ; ++i )
{
printf("%s",letters[i]);
}
printf("\n");
printf("The alphabet in reverse: ");
for( int i=0 ; i < letter_cnt ; i++ )
{
printf("%s",buffer[i]);
}
printf("\n");
}
BTW, is this homework?
This is a case of operator precedence. When you use buffer[i] = *(char**)letters + add;, the * before the cast is performed before the +, making this code equivalent to (*(char**)letters) + add;. The first part is equivalent to the address of the first element in your array, the string "a". Since using string constant automatically adds a null byte, this points to 'a\0'. It happens that the compiler placed all four strings immediately after each other in memory, so if you go past the end of that string you flow into the next. When you add to the pointer, you are moving through this character array: 'a\0b\0c\0d\0'. Notice that each character is 2 bytes after the last. Since this is only true because the compiler placed the 4 strings directly after each other, you should never depend on it (it won't even work if you tried to re-reverse your other string). Instead, you need to put in parentheses to make sure the addition happens before the dereference, and use the 4 byte pointer size. (Of course, as pointed out by Nicholas, you shouldn't assume the size of anything. Use sizeof to get the size of a pointer instead.)
buffer[i] = *((char**)letters + add);
char *letters[] = {"a","b","c","d"};
I think you didn't get the pointer arithmetic correctly. letters is an array of pointers and when incremented by 1 makes to go to next row.
letters + 1 ; // Go to starting location of 2 row, i.e., &"b"
char *letters[] = { "abc" , "def" } ;
(letters + 1) ; // Point to the second row's first element, i.e., &"d"
*((*letters) + 1) ; // Get the second element of the first row. i.e., "b"

Resources