New to forum, question on C

I am working on the Extra Credit on ex10 and just need a nudge on how to approach this. Please no answers, just looking for some friendly push in the right direction.

Hey @abbyrjones72, I saw your email but I’ll answer you here. So, how about you start off with writing up what you tried, what you’re struggling with, and what you think might be the answers. Then I can better give you some hints on where to go.

I’m actually going to spend a week or two on nested loops in hopes of mastering them. These are my weakness, and there is no excuse for that, so I will come back to the lessons when I have done at least 40 hours on my own of practice.

Nah, don’t do that. Punishing yourself for some kind of “failure” isn’t going to help you learn the topic. Talk to me. Take the time to explain out what the extra credit is, what you’ve tried so far, show me some code, and what you think the answer might be. You’d be shocked how well this works to help you figure it out, and if it doesn’t then I can help you figure it out.

Okay let me work something up and I will send it. I have some things to do today, but tonight I will have time to devote to this.

I cancelled my plans.

Here is what I have so far. I am trying to dynamically count the number of args and pass them into the second loop where I used if-elseif statements.

It compiles with 1 warning but doesn’t not accept arguments.

#include <stdio.h>

int main(int argc, char *argv[])
{
  if (argc != 3) {
    printf("ERROR: There needs to be one argument.\n");
    return 1;
  }

  int i = 0;
  int j = 0;
  char letter = '\0';
  for (j = 0; j <= argc; j++) {
    for (i = 0, letter = argv[argc][i]; letter != '\0'; i++) {
        if(letter == 'A' || letter == 'a') {
          printf("%d: 'A'\n",i);
        } else if (letter == 'E' || letter == 'e') {
          printf("%d: 'E'\n", letter);
        } else if (letter == 'I' || letter == 'i') {
          printf("%d: 'I'\n", i);
        } else if (letter == 'O' || letter == 'o') {
          printf("%d: 'O'\n", i);
        } else if (letter == 'U' || letter == 'u') {
          printf("%d: 'U'\n", i);
        } else if (letter == 'Y' || letter == 'y') {
          if (i > 2) {
            printf("%d: 'Y'\n", i);
          }
        } else {
          printf("%d: %c is not a vowel\n", i, letter);
        }
      }
  }

    return 0;
  }

Ah! Ok, let me drop some clues:

  1. You have i and you have j. j is for the outer loop right? Why do you have argv[argc][i] then? Where’s j?
  2. You want to set letter to each letter right? You set it to the first but… I mean, you do i right…where’s letter?
  3. Pro-tip: you are trying to debug too much. What if you gutted (as in, deleted the contents of the inner for-loop) the inner for-loop handling i, and just printed out j, i, and the letters? Get the loop working, then put your monster if-statement back in.

Let me know if you need more clues.

Okay this is what I have so far and it is working for under the conditions of the first program, accepting only one argument. A few questions:

  1. Why is the program itself considered an argument? (argc != 2)

  2. Why can’t we substitute ‘letter’ for ‘argv[1][j]’ after initializing it in the for loop? I figured this one out lol. Nvm.

          #include <stdio.h>
           int main(int argc, char *argv[]) {
    
             if (argc != 2) {
              printf("ERROR: There needs to be at least one argument.\n");
              return 1;
             }
    
           int i, j = 0;
           char letter = '\0';
           for (i = 0, j = 0, letter = argv[1][j]; argv[1][j] != '\0'; i++, j++) {
             char letter = argv[1][j];
    
             if(letter == 'A' || letter == 'a') {
               printf("%d: 'A'\n",i);
             } else if (letter == 'E' || letter == 'e') {
               printf("%d: 'E'\n", i);
             } else if (letter == 'I' || letter == 'i') {
               printf("%d: 'I'\n", i);
             } else if (letter == 'O' || letter == 'o') {
               printf("%d: 'O'\n", i);
             } else if (letter == 'U' || letter == 'u') {
               printf("%d: 'U'\n", i);
             } else if (letter == 'Y' || letter == 'y') {
               if (i > 2) {
                 printf("%d: 'Y'\n", i);
               }
             } else {
               printf("%d: %c is not a vowel\n", i, letter);
             }
            }
         return 0;
           }

First up, get rid of the if-statement. That means cut it out entirely. It is dead to you. It must die for you to see the light. Remove it. Delete it. This is the only way.

Now some answers:

  1. Because that’s how it’s always been. Giving you the name of the program lets you write 1 program that can change what it does based on how it’s named. Back in the day this saved space. Now it’s just annoying.
  2. You have already set letter to argv[1][j]. Why do you want to do it twice? Just get rid of that line.

Now for a new clue:

Why did you get rid of the two loops and replace them with one loop that now has an i, and a j, but then you don’t use i and just use 1?

I suggest you delete this code and try again. Go back to that code you showed me first as that’s more correct than this code. Now, you have to do this following:

  1. Keep both for loops.
  2. Delete the entire contents of the inner for-loop. No if-statement.
  3. Put a single: printf(“i=%d, j=%d\n”, i, j) inside the inner for-loop that just prints what i and j are doing.
  4. Study this ruthlessly until you know what i and j are doing. Hint: it’s a 2 dimensional grid. You keep doing only one dimension of the grid, but you keep creating 2 variables for coordinates but then not using both to go through the grid. Update: in fact, write out your characters on a piece of grid paper and match the i,j to your piece of grid paper.
  5. If you still can’t get it, then consider renaming the i, j variables to x,y so that they match what you know about 2d grid coordinates.
  6. Once you understand how two for-loops increment the i,j (or maybe x,y) variables, DO NOT WRITE MORE CODE. Stop there, come back with this code, and write me an explanation of two for-loops.

This will work but you have to recognize something I see you doing:

You are in a hurry to be awesome at C. So, to do that you are writing a ton of C code to pretend to be an expert, but that’s not how I write C code. I write C code in tiny chunks and break the problems down into little steps. I don’t write reams and reams of C code and then debug it. For example, I would get the out loop right, test it, inner loop right, test it, first part of if right, test it, next part of if, etc.

That means, you need to stop rushing. You need to do this lock step, 1 tiny thing at a time, slow down, do not jump ahead, and do it in tiny logical working chunks. Get one tiny thing working, then move on.

Try that, come back with your new for-loop-only code and an explanation.

I am in a hurry, yes. I am not pretending to be an expert. I know nothing about C and I am here to learn. I will do as you say and get back to you with the loop. And I will slow down for sure. It’s something I’ve always done which is why I am having this problem. Thank you for helping! :slight_smile:

Yep, rushing your learning is just going to frustrate you and keep you from progressing. Take it slow. Incidentally, I code low as hell. But I’m consistent so it’s a good strong pace and I end up doing better work faster because of it. It’s better to go slow, be accurate and thoughtful, and then as you get comfortable you just speed up but without errors.

If I can use learning to ride a bicycle as an example: I learned to ride a bike by going slow with training wheels and being careful, and then when I was able to go fast and stay up on my own the training wheels came off. You’re kind of hopping on a motorcycle and flying at 120mph then slamming into a wall and jumping up and going “Why doesn’t this work?!”

That last thing actually did happen to me as a kid on a mini motorbike lol. I crashed into a barn door that was leaning against the barn and it trapped me for 15 minutes until someone rescued me lol.

I know what the inner loop is doing now, and how it increments based solely on the conditions in it before exiting and going for another iteration of the outer loop. I have done some examples to make myself learn it.

Just simple i and j loops that go to 9 each, but I realize now why it’s doing 10 of the first i[0], then 10 of the following i[1], i[2],…

Okay this is my understanding of two for loops. (in the comments)

image

Ehhhhhh, that’s too complicated. I think what you’re doing is you’re combining the two forloops into one thing when they’re two totally separate things. Also, this is good to read as it shows me what you’re thinking so it’s easier to fix it. What’s going on is:

  • for each i from 0 to 9
    • for each j from 0 to 9
      • print i and j

The key to your misunderstanding is you have a comment saying what the two for-loops do only on the first for-loop. There are two, so you have an outer loop, and an inner loop. You have to disconnect them and treat them as separate entities that do one job.

Backup your code.

So, now let’s strip this down further. Rip out everything except the for(i) loop (outer loop), and print just i. Now, see how that goes from 0-9.

Now, put restore your code from your backup and remove the outer loop. See how j now changes only from 0-9?

Ok, now restore your backup and run it again in your backup version, but notice how your outer loop runs one step, and then it runs all of the for(j) loop 0-9, then the outer loop starts again, and this resets the for(j) loop.

This shows you that what happens is after every iteration of the for(i) loop, the contents are reset, so then your for(j) loop starts over.

Think that over then write me back a new explanation of what’s going on, and then answer this question:

  • How do these two for-loops then map over a 2d grid?
  • How do these two for-loops then map over a 2d grid?

The outer loop handles the height of the grid while the inner handles the width?

I know that loops aren’t language specific, but I bought your LPythonTHW book and want to change gears a bit and come back to C. I feel that Python is a better general language for my knowledge at this time (I’m getting another masters in Data Analytics and we are using Python and R). I’ll see you on the Python boards!

I do understand how they are independent loops now, however. I was mixing up my thinking because sometimes we can make j<i and then the inner loop is dependent on the outer loop. In my example that wasn’t the case. Is that right?

Uh yes, if you did that inside the inner loop then it’d get weird, and actually you wouldn’t do that unless you have a specific algorithm you were doing.

If C is your first language then I highly recommend you go do Python first. C is a terrible language, whether it’s your first or 20th. It is not fun to learn, has too many gun-foot scenarios, and won’t help you be any better as a programmer at first. Go learn Python. Then I’d say, JavaScript or Ruby, THEN try C.

Java is the language I am most familiar with. I have an intermediate knowledge of it, along with some design patterns like Builder and Factory. However, I wanted to learn C because it was closer to the hardware. Python is the goal right now because of the year-long code school I am hopping into. Your book has already helped a ton.

Ah, then I’d say you definitely want to go Python then C. Python is actually really close to Java in its design, but with a simpler syntax. That’ll get your brain back into coding and then C can come after that. C’s difficult is mostly in dealing with the platform.