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.
Related
Why this program can compiling and run but the result is out of my expectation?`
#include<stdio.h>
int main(void)
{
char *message="hello";
for(int i=0;*message!='\0';i++)
{
printf("%c",message[i]);
}
return 0;
}
But this one can meet my expection.(print "hello" rightly)
int main(void)
{
char *message="hello";
for(int i=0;*message!='\0';i++)
{
printf("%c",*message++);
}
return 0;
}
In the C language,arr[i] is equal to *arr.But in the cases I show above,the result is totally different,when I run them in the devc++.Due to my limited knowledge ,I can't understand this.
Because I'm a student who is going to be a freshman after this summer vacation and only have some konwledge about C language,please answer my question in a more acceptable way. Thanks in advance!
***sorry ,the problem is caused because of my carelessness.I have learned my mistake.
In the C language, arr[i] is equal to *arr....
No, *arr is equal to arr[0].
In your first example, you type message++ which make et points on the next character.
So, the first code can be corrected that way:
for(int i=0; message[i]!='\0'; i++)
{
printf("%c",message[i]);
}
And the second can be simplified: (you don't need i):
for( ;*message!='\0'; )
{
printf("%c",*message++);
}
In the first code, the pointer message isn't changed and what the pointer message points at is also not changed, so the condition *message!='\0' is always true (doing 'h'!='\0').
Therefore, i will continuously be incremented and become so large that message[i] goes out of a region where access is allowed.
The condition should be message[i]!='\0' to avoid this error.
If you want to stick to use * operator for some reason, it should be *(message+i)!='\0'.
I rewrite the program with a slightly different appearance
#include<stdio.h>
int main(void)
{
char *message="hello";
for(int i=0; 'h'!='\0';i++) // notice the change here
{
printf("%c",message[i]);
}
return 0;
}
You see the problem now?
*message is always h, it's not changing with the loop iteration. The comparison is meaningless here, it does not terminate the loop as expected.
You need to ensure that you change the pointer to the next address every time you iterate, to ensure you are checking the value of the next element.
You can make use of the index value, like
for(int i=0; * (message + i) !='\0';i++)
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.
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.
What I want to do is reverse a string of numbers that the user enters. what happens is it compiles and runs till i hit enter after the scanf. then I get some Microsoft runtime error... what's going wrong???
NOTE: this is homework, but i've got the logic figured out. what baffles me is this error.
#include <stdio.h>
int main()
{
unsigned int giveStr = 0;
char* charIt;
printf("Enter a number to be reversed.\t");
scanf("%d", &giveStr);
fflush(stdin);
sprintf(charIt, "%d", giveStr);
revStr(giveStr);
getchar();
return 0;
}
revStr(unsigned int n)
{
char buffer[100];
int uselessvar, counter = 0;
for (; n > 0;)
{
uselessvar = sprintf(&buffer[counter], "%d", n);
counter++;
}
for (counter = 0; counter > 0;)
{
printf("%c", buffer[counter]);
counter--;
}
return 0;
}
EDIT: flushing stdin for newlines :/ and also image here just not with that program. with mine.
You are trying to access memory which is not allocated in:
sprintf(charIt, "%d", giveStr);
Change char* charIt; to char charIt[50]; and all should be well (well, at least the segmentation fault part)
Also... pass charIt to revStr, as charIt contains the string with our number.
Then, a simple for loop in revStr will do the trick (what was the purpose of the second one, anyway?)
void revStr(char *giveStr)
{
int counter;
for (counter = strlen(giveStr)-1; counter >= 0; counter--)
{
printf("%c", giveStr[counter]);
}
printf("\n");
}
This will print each char our char representation has from the last one till the first one. You should read more on for loops.
For your home work problem, if you have the K&R book, turn to section 3.5 and read it thoroughly.
Note the functions reverse() and itoa(). They should give you a pretty good idea on how to solve your problem.
How does your program get out of the for (; n > 0;) loop? Won't counter simply increase until you get a bus error?
ED:
Respectfully, I think the claim that "i've got the logic figured out" is a little optimistic. :^) Doubtless someone will post the way it should have been done
by the time I'm done writing this, but it's probably worth drawing attention to what went wrong (aside from the memory allocation problems noted elsewhere):
Your first loop, "for (; n > 0;)", is strange because you're printing the entire number n into the buffer at counter. So why would you need to do this more than once? If you were selecting individual digits you might, but you're not, and obviously you know how to do this because you already used "sprintf(charIt, "%d", giveStr);". [Aside: giveStr isn't a great name for an unsigned integer variable!]
Your second loop also has strange conditions: you set counter to 0, set the condition that counter > 0, and then decrease counter inside. This obviously isn't going to loop over the characters in the way you want. Assuming you thought the first loop was character-by-character, then maybe you were thinking to loop down from counter-1 to 0?
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.