C For Loop Comparison Using Function Doesn't Wait - c

This is kind of strange, imo, I have a for loop that does a comparison
using the return value from a function.
for (size_t i = 0; i < func(val); i++) {
printf("Value from array modified in func = %u", values[i]);
}
The issue is the loop seems to run before the function is finished, if have a printf in the called function some output occurs before the output of the loop, expected, and some after, not expected. The function is only called in the for loop comparison so output should all happen before for loop's output. If I use a var instead such as:
size_t temp = func(val);
for (size_t i = 0; i < temp; i++) {
printf("Value from array modified in func = %u", values[i]);
}
Then everything works correctly, this is rather odd to me, I'm not using threads so this should all be synchronus right? So why would the loop not wait for func(val) to return?
Here's the original code (cutting out a bunch of comments):
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdlib.h>
#define SUITS 4
#define FACES 13
#define CARDS 52
#define HAND 5
typedef struct {
unsigned int suit;
unsigned int face;
} card;
size_t checkX(card hand[HAND], unsigned int faces[HAND], unsigned int num);
int main() {
card hand[HAND] = {{1,1},{1,7},{1,1},{1,4},{1,7}};
const char *suit[SUITS] = {"Hearts", "Diamonds", "Clubs", "Spades"};
const char *face[FACES] = {"Ace", "Deuce", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Jack", "Queen", "King"};
unsigned int matchingFaces[HAND] = {0};
for (size_t i = 0; i < checkX(hand, matchingFaces, 2); ++i) {
printf("Pair of %s%s\n", face[matchingFaces[i]], matchingFaces[i] == 5 ? "es" : "s");
}
}
size_t checkX(card hand[HAND], unsigned int faces[HAND], unsigned int num) {
size_t facePos = 0;
for (size_t i = 0; i < HAND - 1; i++) {
size_t count = 1;
for (size_t j = i + 1; j < HAND; j++) {
printf("%u == %u && %u != %u\n", hand[i].face, hand[j].face, hand[i].face, faces[facePos]);
if (hand[i].face == hand[j].face && hand[i].face != faces[facePos]) count++;
}
faces[facePos] = hand[i].face;
if (count == num) facePos++;
}
return facePos;
}
Some of this isn't my code, I was given a basic card shuffling type of program and told to modify it to deal a hand and check for pairs/three of a kind. Like I said this does work when I set the return value of checkX as a variable and then compare i to that instead of directly, I just don't know why. I've tried disabling gcc optimization, which didn't seem to make a difference.
Output from direct func comparison:
1 == 7 && 1 != 0
1 == 1 && 1 != 0
1 == 4 && 1 != 0
1 == 7 && 1 != 0
7 == 1 && 7 != 0
7 == 4 && 7 != 0
7 == 7 && 7 != 0
1 == 4 && 1 != 0
1 == 7 && 1 != 0
4 == 7 && 4 != 1
Pair of Deuces
1 == 7 && 1 != 1
1 == 1 && 1 != 1
1 == 4 && 1 != 1
1 == 7 && 1 != 1
7 == 1 && 7 != 1
7 == 4 && 7 != 1
7 == 7 && 7 != 1
1 == 4 && 1 != 7
1 == 7 && 1 != 7
4 == 7 && 4 != 1
Output from indirect comparison of func using variable:
1 == 7 && 1 != 0
1 == 1 && 1 != 0
1 == 4 && 1 != 0
1 == 7 && 1 != 0
7 == 1 && 7 != 0
7 == 4 && 7 != 0
7 == 7 && 7 != 0
1 == 4 && 1 != 0
1 == 7 && 1 != 0
4 == 7 && 4 != 1
Pair of Deuces
Pair of Eights
I know this code isn't the nicest but I had to work with what was given and just need to make it work, so this question is just out of curiosity.

for (size_t i = 0; i < func(val); i++) {
printf("Value from array modified in func = %u", values[i]);
}
func(val) gets called multiple times here, each time a decision needs to be made whether to continue the loop or not, you can picture it as
size_t i = 0;
if (i < func(val)) {
printf(.....);
i++;
if (i < func(val)) {
printf(.....);
i++;
if (i < func(val)) {
printf(.....);
i++;
if (i < func(val)) {
printf(.....);
i++;
....and so on......
}
}
}
}
So you can see, func(val) may get called multiple times.

A rather good, but a little out of date, section of the great book "The C Programming Language", by Kernighan and Ritchie, re-state a for loop to the equivalent:
{
size_t i = 0;
while (i < func(val)){
printf("Value from array modified in func = %u", values[i]);
i++;
}
}
(The outer braces are mine and are necessary since you can now declare a variable inside the first "expression" in the for loop.)
If you write the loop this way, it's plain to see that func(val) is re-evaluated on each iteration. That is what is causing the effects you observe. (Note that not all languages do this, VBA and VB6 are two examples where the end condition of the for loop is not re-evaluated.)
Because of this, if func(val) is an expensive function and your algorithm doesn't require repeated evaluation, you might want to consider pre-computing the value in advance. Some compilers may optimise out the re-evaluation especially if you are using a standard function like strlen for example, but such an optimisation is a very tricky science.

Related

Displaying a message when a certain array element is present in C

This program displays certain messages when some of the elements are 'y' or if all of the elements are 'n'.
My question is about this line: someElements |= array[i] == 'y'.
I understand that it can be written in this way: someElements = someElements | array[i] == 'y'.
I'm just asking for an explanation why does it work?
#include <stdio.h>
int main()
{
char array[3] = { 0 };
int i;
for (i = 0; i < 3; i++) {
do {
printf("\nElement No.%d [y/n]: ", i + 1);
scanf(" %c", &array[i]);
if (array[i] != 'y' && array[i] != 'n') {
printf("Must be a lowercase 'y' or 'n'\n");
}
} while (array[i] != 'y' && array[i] != 'n');
}
int someElements = 0;
for (i = 0; i < 3; i++) {
someElements |= array[i] == 'y';
}
if (someElements) {
printf("\nSOME of the elements = y.\n");
}
else{
printf("\nNONE of the elements = y.\n");
}
return 0;
}
Code link
The result of array[i] == 'y' is a boolean true or false. It can be implicitly converted to the int value 1 or 0 (respectively).
Then it's easy to create a bitwise OR table for the possible combinations of someElements | array[i] == 'y':
someElements
array[i] == 'y'
someElements | array[i] == 'y'
0
0
0
0
1
1
1
0
1
1
1
1
So if any of the values are 1 then the result will be 1.
From this follows that if any of the characters in the array is equal to 'y' then the end result of someElements after the loop will be 1. Which then can be implicitly converted back to a boolean true in the following if condition.
Bitwise OR:
Returns true if either bit is true.
Truth table:
A | B | A | B
-------------
0 | 0 | 0
1 | 0 | 1
0 | 1 | 1
1 | 1 | 1
From this, we can conclude that
someElements = someElements | array[i] == 'y;
as someElements has been initialized with 0, or false, it will remain false until array[i] = 'y' returns 1, or true.
Aside: On the last iteration, i + 1 would access out of bounds memory.
The key insight is for a given binary value x:
0 | x == x
1 | x == 1
We initialize the variable someElemenets to 0 (false) so we are in the first case. someElemenets will remain 0 till we encounter an 'y' in the array. It now becomes 1 and will remain so irregardless of the remaining input. Think of it as a one-way (light) switch.
You could just terminate the loop early instead:
someElements = 0;
for (i = 0; i < 3 && !someElements; i++) {
someElements = array[i] == 'y';
}
and it even clearer if you write it as a function:
int any_y(size_t n, const char array[n]) {
for(size_t i = 0; i < n; i++)
if(array[i] == 'y') return 1
return 0
}
which is specialization of memchr():
someElements = memchr(array, 'y', 3);

for loop is only printing last iteration

I am trying to write a C program that takes a string input from a user and then looks into the input to count the frequency of all the integers in the string. So suppose if the user gives the input:
a11472o5t6
the output would be :
0 2 1 0 1 1 1 1 0 0
my approach involves comparing every character of the string to all 10 digits one by one and if any the character is equal to the digit, it would increment the isdigit number by 1.
the code I wrote for the same is as follows:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int is1 = 0; //initialise integers for checking
int is2 = 0;
int is3 = 0;
int is4 = 0;
int is5 = 0;
int is6 = 0;
int is7 = 0;
int is8 = 0;
int is9 = 0;
int is0 = 0;
int main()
{
char s[100]; //initialise array for string
scanf("%s", s); //scan string input
//now all characters of the string are stored in the array s
for (int i = 0; i < strlen(s); i++) //loop to iterate over all the elements in the array
{
if (strcmp(&s[i], "0") == 0)
{
is0 = is0 + 1;
}
if (strcmp(&s[i], "1") == 0)
{
is1 = is1 + 1;
}
if (strcmp(&s[i], "2") == 0)
{
is2 = is2 + 1;
}
if (strcmp(&s[i], "3") == 0)
{
is3 = is3 + 1;
}
if (strcmp(&s[i], "4") == 0)
{
is4 = is4 + 1;
//printf("%d", is4);
}
if (strcmp(&s[i], "5") == 0)
{
is5 = is5 + 1;
}
if (strcmp(&s[i], "6") == 0)
{
is6 = is6 + 1;
}
if (strcmp(&s[i], "7") == 0)
{
is7 = is7 + 1;
}
if (strcmp(&s[i], "8") == 0)
{
is8 = is8 + 1;
}
if (strcmp(&s[i], "9") == 0)
{
is9 = is9 + 1;
}
}
printf("%d ", is0);
printf("%d ", is1);
printf("%d ", is2);
printf("%d ", is3);
printf("%d ", is4);
printf("%d ", is5);
printf("%d ", is6);
printf("%d ", is7);
printf("%d ", is8);
printf("%d ", is9);
}
I expected the code to iterate over and over for the entire length of the string and and update values of the isdigit series every time a number was successfully found. However whenever I run the code only the last digit seems to find its place in the output .
for example if I type 54 as an input the expected output is
0 0 0 0 1 1 0 0 0 0
however the output my code seems to be giving is
0 0 0 0 1 0 0 0 0 0
likewise the number 45 also has the same expected output
0 0 0 0 1 1 0 0 0 0
but the output I am receiving is
0 0 0 0 0 1 0 0 0 0
which looks like the code overwrites any operation that occurred in the previous iteration, but I can't seem to understand why and how to fix it.
On my part I checked if the characters were being called properly one by one and that all characters were being compared, where I found no problem. I also looked up other answers on stack overflow and elsewhere, but was I am a beginner and most answers were written in reference to languages that I can't understand, so I was unable to relate to the solution they were being told. the closest I got was someone who was using a single variable repetitively thus overwriting it in each iteration. however I have declared sufficient variables( one for each digit from 0-9), so that shouldn't be the problem in my code either.
while I know this question could be solved easily using arrays, I would like to know what I was doing wrong here to avoid any such mistakes in the future.
When you do if (strcmp(&s[i],"1")==0) you are comparing strings, not individual characters, which is why only the last character is counted. It's the only one matching.
Example:
If s == "a11472o5t6" and you use strcmp(&s[1], "1"), you would be comparing the string "11472o5t6" with the string "1", which clearly will not be equal.
You want if(s[i] == '1') etc. to do the comparisons of individual characters instead.
And you are correct about using arrays instead. It'd certainly be easier.
Example:
#include <ctype.h>
#include <stdio.h>
int main() {
const char *str = "a11472o5t6";
int ints[10] = {0};
for (const char *chptr = str; *chptr != '\0'; ++chptr) {
if(isdigit((unsigned char) *chptr)) ++ints[*chptr - '0'];
}
for (int i = 0; i < 10; ++i) printf("%d %d\n", i, ints[i]);
}
Output:
0 0
1 2
2 1
3 0
4 1
5 1
6 1
7 1
8 0
9 0

Evaluate 2 consecutive integers in an array into a character

What I want the program to do is to evaluate the 2 consecutive integers after another in a set of array, then convert these integers to a corresponding character.
For example, if I have array[10] = {4 2 3 2 5 3 5 3 6 3}, the first 2 ints 4 2 will be converted into "H", 3 2 = E, 5 3 = L and so on until it prints the word HELLO. The program should accept a list of integers.
This is what I've done so far..
#include <stdio.h>
#include <stdlib.h>
int main() {
int i=0, j=0, k=0;
int array[1000];
char space;
printf("Input integers to convert into a string: ");
do {
scanf("%d%c", &array[i], &space);
i++;
} while(space != '\n');
for(/*what should I include here?*/)
if (array[0] == 2 && array[1] == 1)
printf("A");
else if (array[0] == 2 && array[1] == 2)
printf("B");
/* and so may else ifs*/
}
Something like this should work. Instead of going through the for loop one int at a time, it would probably be best to do two at a time.
for(int i = 0; i < 1000; i += 2){
if (array[i] == 2 && array[i + 1] == 1)
printf("A");
else if (array[i] == 2 && array[i + 1] == 2)
printf("B");
/* and so may else ifs*/
}
I would create a function that converts the integers to the characters.
char int_to_char(int val)
{
if(val == 21)
return 'A';
if(val == 22)
return 'B';
if(val == 42)
return 'H';
if(val == 32)
return 'E';
if(val == 53)
return 'L';
if(val == 63)
return 'O';
// I don't see you pattern, so I don't know which value
// is which character
return '?';
}
I don't see your pattern here.
Then your loop would look like:
// i is the number of entered values
// making sure that the end condition is even
for(int j = 0; j < i&1 ? i - 1 : i; j += 2)
{
printf("%c", int_to_char(array[j] * 10 + array[j+1]));
}
This would print HELLO with the input 4 2 3 2 5 3 5 3 6 3.

just starting to learn c for loop

I am supposed to make a dice game that plays multiple times. I am not really looking for the answer, kind of looking to see what I am doing wrong. I would expect the for loop to assign the int i a value of 0, then run the dice rolls, then add one to i, until i is > 50. Thanks in advance.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
main(){
int rollDie1, rollDie2, keyValue = 0, win = 0, lose = 0, reroll = 0, i;
srand(time(NULL)); // call this only once – seed the random generator
for (i = 0 ; i < 50 ; i++);
{
rollDie1 = rand() % 6 + 1; // in the range of 1 - 6
rollDie2 = rand() % 6 + 1; // in the range of 1 - 6
keyValue = rollDie1 + rollDie2;
if ( keyValue == 7 || keyValue == 11 )
{
printf ("Player wins on the first roll \n");
}
if ( keyValue == 2 || keyValue == 3 || keyValue == 12 )
{
printf("Sorry, you lost on the first roll \n");
}
if ( keyValue == 4 || keyValue == 5 || keyValue == 6 || keyValue == 8 || keyValue == 9 || keyValue == 10 )
{
printf("Reroll! \n");
}
}
system("pause");
}
There's a ; at the end of the for loop that shouldn't be there.
for (i = 0 ; i < 50 ; i++);
should be
for (i = 0 ; i < 50 ; i++)
otherwise there is nothing in the for-loop and what's in the {} will only be executed once, as that's a separate statement.
You have a semicolon at the end of the loop:
for (i = 0 ; i < 50 ; i++);
So it does nothing 50 times. You simply need to remove the semicolon so that your brackets {} will actually encapsulate the lines of your code that are supposed to be in the for loop. If you don't have an open bracket { immediately following a for loop, the first complete statement following the for loop will be executed at each iteration. The semicolon is a complete statement that does nothing.
Actually it will run as long as i<50 which is from 0 to 49

histogram of length of words debug [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
#include <stdio.h>
int main (void) {
FILE *fp;
fp = fopen("test.txt", "r");
int char_counter, i, c;
int word_length[12];
char_counter = 0;
for (i = 0; i <= 12; i++) {
word_length[i] = 0;
}
while ((c = getc(fp)) != EOF) {
if (c == '\n' || c == '\t' || c == ' ')
{
word_length[char_counter] = word_length[char_counter] + 1;
char_counter = 0;
}
else {
++char_counter;
}
}
for (i = 0; i <= 12; i++) {
printf("%d %d\n", i, word_length[i]);
}
return 0;
}
test.txt:
blahblahblah blahblah blah bla bl b b
Output:
0 0
1 1
2 1
3 1
4 1
5 0
6 0
7 0
8 1
9 0
10 0
11 0
12 -1 <-- ??
Expected output looks the same but there should be a 1 at row 12 and not -1. I don't really understand how I got a negative number.
The code
int word_length[12];
means that you have 12 items in the list numbered 0 .. 11
The trying to access item 12 you get undefined behaviour.
Look at this snippt:
int word_length[12];
char_counter = 0;
for (i = 0; i <= 12; i++) {
word_length[i] = 0;
}
Did you find the bug? Hint: Check the number 12 and the operator <= again.
Your int word_length[12]; that means it can store max 12 int number which are 0 to 11,
So, word_length[12] does not get accessible, so its give some garbage value.
You need to do int word_length[13]; and your issue ll be resolved.
KnR Exercise 1-3
#include
#define TAB_STOP 8
#define MAX_WORD_TABS 4
#define MAX_WORD MAX_WORD_TABS * TAB_STOP
int main() {
int c, i, is_first = 1, skip_space = 1, skip_tab = 0;
long word_c = 0, word_l = 0;
while ((c = getchar()) != EOF) {
if (c != ' ' && c != '\t' && c != '\n') {
word_l++;
skip_space = 0;
if (is_first) {
++word_c;
is_first = 0;
}
putchar(c);
} else {
is_first = 0;
if (!skip_space) {
if (word_l 0; --word_l)
printf("|||||"); //putchar('|');
putchar('\n');
skip_space = 1;
}
}
}
}
You can use redirection (<, > or >>) on UNIX for input and output of the program... File handling isn't necessary.

Resources