C for loop optimisation by embedding statements into loop-head itself - c

Just wondering if these variations of for loops are more efficient and practical.
By messing with the c for loop syntax i can embedd statements that would go in the loop-body into the loop-head like so:
Example 1:
#include <stdio.h>
int main(int argc, char ** argv)
{
// Simple program that prints out the command line arguments passed in
if (argc > 1)
{
for(int i = 1; puts(argv[i++]), i < argc;);
// This does the same as this:
// for(int i = 1; i < argc; i++)
// {
// puts(argv[i]);
// }
}
return 0;
}
I understand how the commas work in the for loop it goes through each statement in order, evaluates them then disregards all but the last one which is why it is able to iterate using the "i < argc"condition. There is no need for the final segment to increment the i variable as i did that in the middle segment of the loop head (in the puts(argv[i++]) bit).
Is this more efficient or is just just cleaner to seperate it into the loop body rather than combine it all into one line?
Example 2:
int stringLength(const char * string)
{
// Function that counts characters up until null terminator character and returns the total
int counter = 0;
for(counter; string[counter] != '\0'; counter++);
return counter;
// Same as:
//int counter = 0;
// for(int i = 0; string[i] != '\0'; i++)
//{
// counter++;
//}
//return counter;
}
This one seems more efficient than the version with the loop body as no local variable for the for-loop is initialised. Is it conventional to do these sorts of loops with no bodies?

Step 1: Correctness
Make sure code is correct.
Consider OP's code below. Does it attempt to print argv[argc] which would be bad?
if (argc > 1) {
for(int i = 1; puts(argv[i++]), i < argc;);
I initially thought it did. So did another user. Yet it OK.
… and this is exactly why code is weak.
Code not only should be correct, better code looks correct too. Using an anti-pattern as suggested by OP is rarely1 as good thing.
Step 2: Since code variations have the same big O, focus on understandably.
Sculpt your code – remove what is not needed.
for (int i = 1; i < argc; i++) {
puts(argv[i]);
}
What OP is doing is a trivial optimization concern.
Is premature optimization really the root of all evil?
Is it conventional to do these sorts of loops with no bodies?
Not really.
The key to the style of coding is to follow your group's style guide. Great software is often a team effort. If your group's likes to minimize bodies, go ahead. I have seen the opposite more common, explicit { some_code } bodies.
Note: int stringLength(const char * string) fails for strings longer than INT_MAX. Better to use size_t as the return type – thus an example of step 1 faltering.
1 All coding style rules, except this rule, have exceptions.

Related

Mastermind game in C(with words)

I am probably not going to get help here because my question is far from being specific (I don't even know what exactly wrong with it) but, according to my professor's tests, there is something wrong with it (wrong in terms of correctness - it doesn't provide correct number of direct and indirect matches) (I have no access to his tests). As far as I have been testing, it passes all of my tests. However, there are over a couple hundred million possible outcomes (I think) and I can't test them all because I don't know how to do automated testing...
Here is my code that performs the "logic" part of the game called mastermind, which is compares a string of randomly generated letter (8 max) with user input string (a guess). I wanted to see if anyone has encountered this game in the past and knows the logic of how it supposed to compare two strings and generate the correct number of exact and inexact guesses.
// userInput->position - a length of a string(max 8)
// userInput->code - randomly generated code
// userInput->arr - user input string
void checkForExactMatch(Data* userInput) {
int i;
for (i = 0; i < userInput->position; i++) {
if (userInput->code[i] == userInput->arr[i]) {
userInput->exactMatch++;
userInput->arr[i] = 'a';
}
else
checkForInExactMatch(userInput, i);
}
}
void checkForInExactMatch(Data* userInput, int i) {
int j;
for (j = 0; j < userInput->position; j++) {
if (userInput->arr[j] == userInput->code[i]) {
userInput->arr[j] = 'a';
userInput->inExactMatch++;
break;
}
}
}
Looking over your code there were a couple of observations to be made. First in your for checkForExactMatch() the call to checkForInExactMatch is inside your for loop. So on the first mismatch you call checkForInExactMatch and when you return from checkForInExactMatch -- you call it again on the next iteration unless your first mismatch just happens to be on the final character.
To address that issue, you should fully determine whether you have an exact match or not, completing the for loop before checkForInExactMatch is called.
In your checkForInExactMatch, you have to decide whether a single common-character or some minimum length substring constitutes an inexact match.
It sounds like you have things worked out, and good job for pushing through to a solution. Depending on how you approached it, keeping a simple flag in checkForExactMatch()such as int matched = 1; and then loop turning your test around
for (i = 0; i < userInput->position; i++)
if (userInput->code[i] != userInput->arr[i]) {
matched = 0;
break;
}
Then it's just a simple test of
if (matched) {
userInput->exactMatch++;
userInput->arr[i] = 'a';
}
else
checkForInExactMatch(userInput, i);
So long as what you have done accomplishes something similar, you are fine. Let me know if you have further questions.

C's For loop's arguments

I want to initialize an 16-cel-long array with 0, 1, 2 and 3 by blocks of four cels. So here is my first attempt at this:
int main(void) {
int t[16];
int i;
for (i = 0; i<=15; t[i++]=i/4)
{
printf("%d \n", t[i]);
}
return 0;
}
However, here is what I get. I know I can do it differently by just getting the affectation into the for loop, but why does this not work?
EDIT: Please do note that the printf only serves to check what the loop did put in the array.
The initialization works fine; you're just printing the cell before initializing it. Remember that the loop increment is done after each iteration. If you unroll the loop, you have:
i = 0; /* i is now 0 */
print(t[i]); /* prints t[0] */
t[i++] = i/4; /* sets t[0] */
/* i is now 1 */
print(t[i]); /* prints t[1] */
t[i++] = i/4; /* sets t[1] */
/* i is now 2 */
print(t[i]); /* prints t[1] */
/* etc. */
As well as the off-by-one errors with the loop begin/end that have been mentioned in other posts, this code:
t[i++]=i/4
causes undefined behaviour because i is read and written without a sequence point. "Undefined behaviour" means anything can happen: the value could be 3, or 4, or anything else, or the program could crash, etc.
See this thread for more in-depth discussion, and welcome to C..:)
I do not understand what you are trying to accomplish, but please let me show you a similar piece of code, first.
int main(void) {
int t[16];
int i;
//edited the code; providing standard way to do the task
for (i = 0; i<=15; i++)
{
t[i]=i/4;
printf("%d \n", t[i]);
}
return 0;
}
EDIT:
The while loop should be written that way:
int i = 0;
while (i<=15){
t[i] = i%4;
i++;
}
Which means set t[i] equal to i%4 and then increment i.
Since you are a beginner, I've updated the for loop and it now provides a standard way to do your task. It's better to have a simple increment on the third for loop command; do the rest of the job inside the for loop, as described above.
#naltipar: Yeah, I just forgot to initialize the first cel, just like grawity pointed out. Actually, the version I wrote for myself was with i++ but even then, since the third expression is executed after each loop, it sent out the same result. But whatever, it is fixed now.
However, I've got another problem which I'm sure I'm missing on but still can't figure it out:
int i = 0;
while (i<=15)
t[++i] = i%4;
This was first:
for(i = 0; i<=15; t[++i] = i%4);
but it resulted with an infinite loop. So in order to make sure that's not a problem specific to for, I switched to while andthe same thing still happens. That being said, it doesn't occur if i replace ++i by i++. I unrolled the whole loop and everything seems just fine...
I'm a beginner, by the way, in case you were wondering.
A clearer way to write this would be much less error-prone:
for (i = 0; i < 16; ++i)
printf ("%d\n", (t[i] = i % 4));
Personally I'd code something that way, but I'd never recommend it. Moreover, I don't really see much benefit in condensing statements like that, especially in the most important category: execution time. It is perhaps more difficult to optimize, so performance could actually degrade when compared to simply using:
for (i = 0; i < 16; ++i)
{
t[i] = i % 4;
printf ("%d\n", t[i]);
}
Even if it is you reading your own code, you make it difficult for your future self to understand. KISS (Keep It Simple, Stupid), and you'll find code is easier to write now and just as easy to modify later if you need to.

Finding a string in a string using function

I am trying to write a function(findString) to find out if character strings are present inside another string. For my function, the first argument is the searched character string and the second is the one trying to be found.
If the string is found, then the location of the source string is returned.
My written code is below:
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
int findstring(char source[], char lookup[]){
int lensource, lenlookup;
lensource= strlen(source);
lenlookup = strlen(lookup);
int i;int j;
for(i=0; i>=lensource; ++i)
for (j=0; j>=lenlookup; ++j)
if (source[i]==lookup[j])
return i;
}
int main(){
findstring("Heyman","ey");
}
If the function worked properly, then the index 2 should be returned.
However, when I run it, nothing is returned. I suppose the problem it that there is something wrong with my approach with the for loop or if statement.
I'm doing this without using strstr
First, there is a function that does this already, called strstr.
Second, your loop is written incorrectly. It should be:
for(i=0; i < lensource - lenlookup + 1; ++i) {
for (j=0; j<lenlookup; ++j)
if (source[i + j]!=lookup[j])
break;
if (j == lenlookup) return i + 1; // edit: had error
// note that return i feels more right, but
// op's spec seems to want i + 1
}
return -1; // no spec on return value for failure, but -1 seems reasonable
Edit: had typo.
Assuming both source and lookup are non-empty strings, then both lenlookup and lensource are strictly positive.
And your for loops are never executed, because
for(i=0; i>=lensource; ++i) {
// do something
}
is understood as (and translated by the compiler to):
i=0;
while(i>=lensource) {
// do something;
// at last
++i;
}
so you understand the initial test i>=lensource is false (at start i==0 but lensource>0) so the loop is never executed
BTW I strongly suggest to compile your code with all warnings and debugging info (e.g. gcc -Wall -g) and to use a debugger (e.g. gdb) to run it step by step and understanding what is happening.
You missed basic input check (what if either source or lookup is NULL, what if lookup is an empty string, what if lookup is longer than source, etc)
The comparison is not performed correctly
Your function doesn't always return a value (what does it return if lookup is not found in source?).
int findstring(char source[], char lookup[]){
// when either input is NULL
if(source==NULL||lookup==NULL)return -1;
int lensource, lenlookup;
lensource= strlen(source);
lenlookup = strlen(lookup);
// when lookup is an empty string
if(lenlookup==0)return 0;
// when lookup is longer than source
if(lenlookup>lensource)return -1;
int i;int j;
for(i=0; i<=lensource-lenlookup; ++i){
bool success = true;
for (j=0; j<=lenlookup; ++j){
if(lenlookup[j]!=lenlookup[i+j]){
success = false;
break;
}
}
if(success)return i;
}
return -1;
}
You may also want to check out other more efficient algorithms like KMP, boyer-moore and rabin-karp.

another char shift C

so i've looked through here and on google and tried various forms to try and accomplish this. it doesn't seem like it should be hard. i've tried getting a value from the char, tried just using math on it since i've read that a char in C is a number to the compiler anyway. what i have is an array of 4 strings. each element is another array of 20 + 1 characters (to include the null \0) what i'm trying to do is shift the value of each character in each string by a predefined amount using a variable "decryption_shift". what i thought i was doing is using 2 for loops, one to do one string at a time, the other to change each character in the strings. i've tried using pointers, tmp variables. yes this is a homework assignment, problem is it's a higher level class and they aren't teaching us methods/functions/syntax, they want us to research and learn on our own how to do it. i've already spent 2 hours trying to figure out this one snippet and don't know where else to turn. any help is greatly appreciated.
~justin
void decrypt_chunks()
{
for (m = 0; m < 0; m++)
{
for (n = 0; n < 20; n++)
{
// int *chunksp = &chunks[m][n];
chunks[m][n] = chunks[m][n] - DECRYPTION_SHIFT;
// *chunksp[m][n]=tmp;
// chunks[m][n]=tmp;
}
}
}
Your problem is here:
for (m = 0; m < 0; m++)
The loop will never execute because the termination condition is met on initialization. Try
for (m = 0; m < 4; m++)
I can't see where DECRYPTION_SHIFT or chunks is defined (and initialized), so make sure you're actually define it globally or in the decrpyt_chunks() function (note: usually you write variables lowercase and macros uppercase, and if DECRYPTION_SHIFT is a variable you should write it in lowercase letters)
for (m = 0; m < 0; m++) while never run, this statement in words would be something like: set m to ziro (btw where did you defined m?) and do the following things as long as m is less than ziro (never the case, as you set it to ziro)
As this seems like a very basic problem, make sure you actually understand what a programming language is and how it works and consider reading one or two books about c (or almost any other programming language, as this homework would be in most modern languages pretty much the same).
To really make this thing interresting, what you basically do is encrypting like Caesar, so to implement this, the code could look similar to this one:
#include <stdio.h>
#include <string.h>
void decrypt_chunks(int decryption_shift);
char chunks[4][21];
int main(int stdr, char *stdv[])
{
strcpy(chunks[0],"Hello World! And Bye");
printf("message string: %s\n", chunks[0]);
decrypt_chunks(1);
printf("encrypted string: %s\n", chunks[0]);
decrypt_chunks(-1);
printf("decrypted sring: %s\n", chunks[0]);
}
void decrypt_chunks(int decryption_shift)
{
for (int m = 0; m < 4; m++)
{
for (int n = 0; n < 20; n++)
{
chunks[m][n] = chunks[m][n] - decryption_shift;
}
}
}

Loops in C - for() or while() - which is BEST?

for() or while() - which is BEST?
for (i=1; i<a; i++)
/* do something */
OR
i=1;
while (i<a) {
/* do something */
i++;
}
The first is the idiomatic way; it is what most C coders will expect to see. However, I should note that most people will also expect to see
for(i = 0; i < a; i++)
Note that the loop starts at zero. This will do something a times. If you're going to write a while loop that is equivalent to a for loop as above I strongly encourage you to write it as a for loop. Again, it is what C coders expect to see. Further, as a for loop it is easier to read as everything (initialization, loop condition, expression to be executed after each iteration) are all on one line. For the while loop they are spread out hindering readability.
Note, however, there are circumstances in which seemingly equivalent for and while loops are actually not. For example:
for(i = 0; i < 10; i++) {
if(i == 5) continue;
printf("%d\n", i);
}
and
i = 0;
while(i < 10) {
if(i == 5) continue;
printf("%d\n", i);
i++;
}
appear at first glance to be equivalent but they are not. The for loop will print 0--9 skipping 5 on the console whereas the while loop will print 0--4 on the console and then enter an infinite loop.
Now, that handles the simple case that you asked about. What about the more complex cases that you didn't ask about? Well, it really depends but a good rule of thumb is this: if you are going to repeat something a fixed pre-determined number of times, a for loop is generally best. Otherwise, use a while loop. This is not a hard-and-fast rule but it is a good rule-of-thumb. For example, you could write
unsigned int v;
unsigned int c;
for(c = 0; v; v >>= 1) c += v & 1;
but I think most C programmers would write this as
unsigned int v;
unsigned int c;
c = 0;
while(v) { c += v & 1; v >>= 1; }
Or, as another example, if you're going to read until the end of a file then you should use a while loop. Thus
FILE *fp;
fp = fopen(path, "r");
while(fgets(buf, max, fp) != NULL) { /* something */ }
instead of
FILE *fp;
for(fp = fopen(path, "r"); fgets(buf, max, fp) != NULL; ) { /* something */ }
Now, reaching into religious territory, this is why I prefer while(1) as the right way to do an infinite loop over for(;;).
Hope that helps.
It depends. What makes the reading most easy should be a guideline IMHO. If you know bounds beforehand you probably should use 'for'. Because it clearly says in one line where the looping starts, it ends and how to go from one element to the other.
Vote up for Dan McG - if the loop has a fixed count, etc., use for - it's more idiomatic. Classic cases of each:
for (i = 0; i < THRESHOLD; ++i) {
something;
}
Vs.
while (foo->next) {
foo = foo -> next;
}
Also: if you find yourself leaving out conditions in your for, consider what it would be like if you reworte it as a while.
At the end of the day: go back and read each version of the loop. Which one stands out more in your mind as "clear" in intent?
Which one makes most sense in the situation.
The for loop tells you it is most probably a fixed count loop. Starting at 1 ending before a.
The while loop doesn't imply any such thing, just that it ends once i >= a (at least from just reading the while (i<a){ at the top).
Of course, this isn't a rule and programmers generally do as they see fit, but it does make it easy to read through code without having to backtrack to comprehend some section.

Resources