Study/C Language

씹어먹는 C언어 혼자 실습 (2)

imaginefuture-1 2024. 10. 16. 22:51

 

for문 실습 이것저것..

for(;;) 무한반복실험 재밌다.. 광기스럽다

 

 

이게 찐 광기아닐까

 
 
for문 공부하는데 문제 풀이에서 벽을 만났다.
 
이거 역시 응용은 늘 어렵다.. 수학문제가 그렇듯..
 


생각 해보기

문제 1 (난이도 : 中)

N 줄인 삼각형을 출력한다. 단, 사용자로 부터 임의의 N 을 입력 받는다. 아래는 N = 3 일 때의 출력 예시 이다.

  *
 ***
*****

 
열심히 기초 예제들 뒤적이며 스스로 코드를 적어봤다. 역시 이론과 실전은 다르다.

#include <stdio.h>
int main() {
int i = 0, n = 0;

printf("몇개의 *수를 입력받을 건가요?");
scanf_s("%d", &n);

for (i = 0; i < n; i++) {
printf("*\n");
}
return 0;

}

 
하니까
임의의 n을 넣으면 n만큼
*
*
*
나온다
 
이걸 어떻게 옆으로 나오게 하지.. 홀수만큼 나오는데 나누기를 해서 나머지가 1인 애들을 출력해야하나
으아에
 
결국 검색해서 답 소스코드를 보는데
 
star가 반복되는 패턴은 이해가 됐는데 아무리 생각해도 gap의 패턴이
분명 값이 줄고있는데 왜 이게 증가인거지.. 2시간을 고민했다.


 

 

나: 

 
응. 내가 한 코드야. #include <stdio.h>
int main() {
int i  = 0, height = 0, gap = 0, star = 0;

printf("몇줄의 삼각형을 원하는가요\n");
scanf_s("%d", &height);

for (i = 0; i < height; i++) {

for (gap = i; gap < height; gap++) {

printf(" ");
}
for (star = 0; star < i * 2 + 1; star++) {
printf("*");
}
printf("\n");
}
return 0;

} 근데 여기서 gap부분이 이해가 안가..

 
gpt:
 
 
네, 코드에서 `gap` 부분이 헷갈릴 수 있어요. 이 부분은 삼각형 모양을 만들 때 **공백을 출력**하는 부분인데, 차근차근 설명해볼게요.

### 코드 구조 설명

#### 1. **외부 for문** (`for (i = 0; i < height; i++)`)
- 이 외부 `for`문은 삼각형의 **줄 수**를 담당합니다. 입력한 `height` 값만큼 반복되며, 각 반복마다 삼각형의 한 줄을 출력합니다.

#### 2. **gap for문** (`for (gap = i; gap < height; gap++)`)
- 이 부분이 바로 **공백**을 출력하는 부분입니다.
- 삼각형을 만들 때, 왼쪽에 공백을 출력해야 별이 가운데 정렬된 모양이 나오게 됩니다.
- 공백의 개수는 **현재 줄(i)**에 따라 변합니다. 
    - 첫 번째 줄에서는 `height - 1`개의 공백을 출력하고,
    - 두 번째 줄에서는 `height - 2`개의 공백을 출력하는 방식입니다.
- 즉, `gap = i`로 시작해서 `height`에 도달할 때까지 공백을 출력하게 됩니다. 

#### 3. **star for문** (`for (star = 0; star < i * 2 + 1; star++)`)
- 이 부분은 **별**을 출력하는 부분입니다.
- 각 줄에서 출력할 별의 개수는 줄 번호에 따라 달라지는데, `i`가 증가할수록 별의 개수도 늘어납니다.
    - 예를 들어, 첫 번째 줄에서는 1개(`i * 2 + 1`), 두 번째 줄에서는 3개, 세 번째 줄에서는 5개... 이런 식으로 진행됩니다.

### gap의 역할
`gap`은 각 줄마다 **왼쪽에 얼마나 많은 공백을 넣을지를 결정**하는 변수입니다. 삼각형의 꼭대기 부분에서는 공백이 많고, 아래로 내려갈수록 공백이 줄어듭니다.

- **첫 번째 줄 (i=0)**: `height`개의 공백을 출력
- **두 번째 줄 (i=1)**: `height-1`개의 공백을 출력
- **세 번째 줄 (i=2)**: `height-2`개의 공백을 출력

이렇게 공백을 점점 줄이면서 별이 가운데 정렬된 삼각형 모양을 만들어 줍니다.

### 예시: 높이 3인 삼각형

1. `i = 0` (첫 번째 줄)
   - 공백(gap): `height - i = 3 - 0 = 3` (공백 3개)
   - 별: `i * 2 + 1 = 0 * 2 + 1 = 1` (별 1개)
   - 출력:  
   ```
      *
   ```

2. `i = 1` (두 번째 줄)
   - 공백(gap): `height - i = 3 - 1 = 2` (공백 2개)
   - 별: `i * 2 + 1 = 1 * 2 + 1 = 3` (별 3개)
   - 출력:  
   ```
     ***
   ```

3. `i = 2` (세 번째 줄)
   - 공백(gap): `height - i = 3 - 2 = 1` (공백 1개)
   - 별: `i * 2 + 1 = 2 * 2 + 1 = 5` (별 5개)
   - 출력:  
   ```
    *****
   ```

결과적으로 삼각형 모양이 이렇게 출력됩니다:
```
   *
  ***
 *****
```

### 요약
`gap`은 각 줄에서 별을 출력하기 전에 **얼마나 많은 공백을 출력할지**를 결정하는 역할을 합니다. `i`가 증가할수록 출력하는 공백의 수는 줄어들게 되어, 별이 **가운데 정렬된 삼각형** 모양을 만들게 됩니다.

혹시 더 궁금한 부분 있으면 알려주세요!

 
나:

height - i왜 빼는거야. i는 height 값만큼 반복되고 그만큼 줄 수를 만드는데 그 반복되는걸 gap에 넣고 gap이 height의 값까지 또 반복되는건데. 더 계속 더해져야하는거아니야?
 

(내가 이해 안됐던 부분)
 


 

그렇게
밥시간이 다되서 밥 먹으러 갔다.
 
 
뼈다귀해장국 저녁으로 먹으러 가서 주문하고 기다리는 동안 이 블로그 글을 읽고있다가
깨달았다.
 
https://m.post.naver.com/viewer/postView.nhn?volumeNo=8390558&memberNo=1991839

 

<C언어 강좌> 반복문&별찍기

[BY 구자민] -목차-0. while문 사용법, for문 사용법 -while문, for문 1. for문 while문으로 바꾸기 –1,...

m.post.naver.com

 


 
값이 줄지만
반복 횟수는 늘고있었다
 
그래서 증가였다.
 
수학적인 개념에서 내가 gap을 값으로 보고있었던거다.
 
그래서 소스코드로 이것저것 실험해봤다..헤헤



나:
 
지피티야. 이렇게 코드 수정하니까
#include <stdio.h>
int main() {
int height  = 0, n = 0, gap = 0, star = 0;

printf("몇줄의 삼각형을 원하는가요\n");
scanf_s("%d", &n);

for (height = 0; height <= n; height++) {

for (gap = height ; gap <= (n - height); gap++) {

printf(" ");
}

for (star = 0; star < height; star++) {
printf("*");
}
printf("\n");
}
return 0;

}  몇줄의 삼각형을 원하는가요
4

   *
 **
***
**** 이런 모양이 나와. gap 변수는 0, 0, 1 7을 반복한건가? 왜그런거지
 
gpt:
 
코드를 수정하면서 발생한 결과에 대해 설명드릴게요! 이 코드에서 별이 의도와 다르게 출력되는 이유는 **`gap` 루프의 조건 설정**에 있습니다. 각 반복에서 공백이 잘못된 방식으로 출력되고 있기 때문입니다.

### 현재 코드 분석
```c
for (gap = height; gap <= (n - height); gap++) {
    printf(" ");
}
```

이 코드는 `gap`을 `height`부터 시작해서 `(n - height)`까지 공백을 출력하도록 설정한 것입니다. **문제는 `(n - height)`가 점점 줄어들기 때문에 공백이 예상한 대로 출력되지 않고**, 줄에 따라 다르게 작동하고 있다는 점입니다. 이 때문에 출력이 왜곡되고 있습니다.

### 각 변수의 값 변화를 살펴볼게요:

1. **첫 번째 루프 (`height = 0`)**:
   - `gap = 0`, `n = 4`, `height = 0`
   - 루프 조건: `gap <= 4` → 5개의 공백 출력 (이것이 잘못된 점)
   - 출력 결과: `"     *"`

2. **두 번째 루프 (`height = 1`)**:
   - `gap = 1`, `n = 4`, `height = 1`
   - 루프 조건: `gap <= 3` → 3개의 공백 출력
   - 출력 결과: `"   **"`

3. **세 번째 루프 (`height = 2`)**:
   - `gap = 2`, `n = 4`, `height = 2`
   - 루프 조건: `gap <= 2` → 1개의 공백 출력
   - 출력 결과: `"  ***"`

4. **네 번째 루프 (`height = 3`)**:
   - `gap = 3`, `n = 4`, `height = 3`
   - 루프 조건: `gap <= 1` → 0개의 공백 출력
   - 출력 결과: `"****"`

### 문제의 원인
문제는 **`gap`을 `height`부터 시작하도록 설정한 것**입니다. `height`는 매 줄이 내려갈수록 커지기 때문에 공백을 점점 적게 출력하는 구조로 되어버렸습니다. 그래서 기대한 삼각형 모양이 아닌, 이상한 공백 처리 결과가 나오게 된 것입니다.

### 해결 방법
공백을 제대로 출력하기 위해서는 **공백의 개수를 `(n - height)`로 정확히 설정**해야 합니다. 공백을 `n - height`개 출력하고, 그다음에 별을 출력하는 방식으로 고쳐야 합니다.

수정된 코드는 다음과 같이 변경될 수 있습니다:

```c
#include <stdio.h>
int main() {
    int height = 0, n = 0, gap = 0, star = 0;

    printf("몇 줄의 삼각형을 원하는가요\n");
    scanf_s("%d", &n);

    for (height = 0; height <= n; height++) {
        // 공백 출력
        for (gap = 0; gap < (n - height); gap++) {
            printf(" ");
        }
        // 별 출력
        for (star = 0; star < height; star++) {
            printf("*");
        }
        printf("\n");
    }
    return 0;
}
```

### 설명:
1. **공백 출력**: `for (gap = 0; gap < (n - height); gap++)`  
   - 공백의 개수는 `(n - height)`로 줄어들도록 하여, 첫 줄에 가장 많은 공백을 출력하고, 아래로 갈수록 공백을 줄입니다.
   
2. **별 출력**: `for (star = 0; star < height; star++)`  
   - 별의 개수는 `height`에 비례해서 출력됩니다.

### 결과 (입력: `n = 4`):
```
   *
  **
 ***
****
```

이제 공백과 별이 정상적으로 출력되어, 원하는 삼각형 모양이 만들어질 것입니다. `gap`을 적절히 설정해 공백을 먼저 출력하고, 별을 뒤따라 출력하도록 바꾸는 것이 핵심이었습니다.

혹시 더 궁금한 부분이 있으면 언제든지 물어봐 주세요!

 

요건 실행 순서를 바꿔봤다.

 
나:
 
for (gap = 1; gap <= (n - height); gap--) 바꾸니까 화면에 아무것도 출력안되고 막 움직여 ㅋㅋ
 
gpt:

하하! 아주 흥미로운 실험을 하셨네요! 😄

문제는 바로 **`gap--`** 때문입니다. `gap--`는 `gap` 값을 1씩 **감소**시키는 연산인데, 그와 동시에 `for`문에서의 조건이 `gap <= (n - height)`로 되어 있어서 **감소하면서도 계속 조건을 만족하는 상황**이 발생하게 됩니다. 결국, 이 루프는 **무한 루프**에 빠지게 되죠.

### 왜 무한 루프에 빠질까요?
```c
for (gap = 1; gap <= (n - height); gap--)
```
이 코드는 `gap`이 1에서 시작해서 점점 줄어듭니다. 그런데 `gap <= (n - height)` 조건은 `gap`이 **작거나 같으면 반복하도록 설정**되어 있어요. 즉, `gap`이 0, -1, -2... 계속 작아지면서 조건을 계속 만족시키게 되죠. 결국 `for`문이 **끝없이 실행**되고, 화면은 출력되지 않으며 프로그램이 멈추게 됩니다.

### 해결 방법
`gap--` 대신 `gap++`로 변경하여 **증가**하도록 하면, 정상적으로 종료됩니다. 원래 목표는 `gap`이 1에서 시작해서 `(n - height)`까지 점차 커지는 것이었으니, `gap++`로 값을 올려주면서 공백을 출력하면 됩니다.

```c
for (gap = 1; gap <= (n - height); gap++)
```

이렇게 수정하면, 공백을 정상적으로 출력하면서 삼각형 모양이 나올 거예요.

### 무한 루프 방지
무한 루프는 가끔 실험하면서 겪는 흔한 상황입니다. 주로 **반복 조건을 잘못 설정하거나**, 변수 값을 증가시켜야 할 때 **감소**시키는 등 조건과 반복 방식이 일치하지 않을 때 발생해요. 이런 경험을 통해 조건을 설정하는 감각을 더 익힐 수 있게 되니, 좋은 실험이라고 할 수 있어요!

또 궁금한 게 있으면 언제든지 물어봐 주세요!
 



gap--로 트리 만들어 보고싶어서 이리저리 검색했다.
그렇게 인터넷 검색하다가 나온 코드가 그 사람이 적어놓은 출력값이랑 다르게 나와서 뭐지 왜지 생각해서
gpt한테 물어보니 왼쪽 공백만 있게 출력되는 모습이 맞다했다.
그래 뭔가 이상하더라..
 
gpt한테 물어봤다 gap--로 트리모양 만들고 싶어요! 도움!
 


gpt:
 
이 코드에서는 사용자로부터 삼각형의 줄 수를 입력받아 **왼쪽 정렬된 직각 삼각형** 모양을 출력합니다. 각 줄에서 별의 개수는 점차적으로 증가하며, 공백을 포함하여 삼각형이 왼쪽으로 정렬된 형태로 출력되도록 되어 있습니다. 

### 코드 설명:

1. **입력 받기**:
   ```c
   scanf_s("%d", &input);
   ```
   - 몇 줄짜리 삼각형을 그릴지 사용자로부터 입력받습니다.

2. **바깥쪽 `for` 루프**:
   ```c
   for (i = 1; i <= input; i++)
   ```
   - 이 루프는 총 `input` 값만큼 반복되며, 매번 한 줄씩 출력합니다. `i`는 현재 줄의 번호를 나타냅니다.

3. **공백 출력 부분**:
   ```c
   for (j = input; j > i; j--)
       printf(" ");
   ```
   - 이 루프는 별을 출력하기 전에 **공백을 출력**합니다. 공백의 개수는 줄 번호(`i`)에 따라 점차적으로 줄어듭니다.
   - 처음에는 `input - 1`개의 공백을 출력하고, 다음 줄에서는 `input - 2`개의 공백을 출력하는 방식입니다.

4. **별 출력 부분**:
   ```c
   for (j = 1; j <= i; j++)
       printf("*");
   ```
   - 이 루프는 각 줄에서 출력할 **별의 개수**를 결정합니다. 첫 번째 줄에서는 별 1개, 두 번째 줄에서는 별 2개, ... 마지막 줄에서는 `input`개의 별이 출력됩니다.

5. **출력 형태**:
   각 줄의 출력 후에는 `\n`을 사용하여 **줄바꿈**을 실행합니다.
   
6. **최종 `i` 값 출력**:
   ```c
   printf("최종 i 값 = %d", i);
   ```
   - 이 코드는 바깥쪽 `for` 루프가 종료된 후 최종 `i` 값을 출력합니다. `i`는 마지막 반복 후 `input + 1` 값이 됩니다. 

### 예시 실행:
사용자가 4를 입력한 경우:
```
몇 줄 짜리 삼각형? : 4
i = 1 :    *
i = 2 :   **
i = 3 :  ***
i = 4 : ****
최종 i 값 = 5
```

### 동작 원리:
- 첫 번째 줄에서는 3개의 공백, 1개의 별을 출력하고,
- 두 번째 줄에서는 2개의 공백, 2개의 별을 출력하는 식으로,
- `i`가 증가함에 따라 공백은 줄어들고 별은 늘어납니다.

코드에 대해 더 궁금한 점이 있거나 수정하고 싶은 부분이 있으면 언제든 알려주세요! 😄
 
`gap--`로 변경해서 트리 모양을 만들고 싶었던 점은 흥미로운 시도예요! 그런데 `gap--`는 공백을 점차 줄여나가는 과정에서 무한 루프에 빠질 가능성도 있어서 어려움을 겪으셨을 겁니다. **트리 모양**에서는 공백과 별이 적절히 조화를 이루어야 하므로, 공백을 줄이는 방식도 정확하게 계산되어야 해요.

우측 공백을 포함한 트리 모양을 만들기 위해서는 `gap--`보다는 **좌우 공백을 모두 컨트롤**할 수 있는 로직이 필요합니다.

### `gap--`를 사용하여 트리 모양 만들기

사실, 트리 모양을 만들 때는 공백을 양쪽에서 컨트롤해야 합니다. 만약 `gap--`을 사용해서도 트리 모양을 만들고 싶다면, **우측 공백을 명시적으로 추가**하는 방법도 있습니다. 예를 들어, 아래와 같이 코드를 수정할 수 있습니다:

```c
#include <stdio.h>
int main() {
    int i, j, input, gap;

    printf("몇 줄 짜리 삼각형? : ");
    scanf_s("%d", &input);

    for (i = 1; i <= input; i++) {
        // 왼쪽 공백 출력
        for (gap = input; gap > i; gap--) {
            printf(" ");
        }

        // 별 출력
        for (j = 1; j <= (2 * i - 1); j++) {
            printf("*");
        }

        // 우측 공백 출력 (선택사항, 트리 형태에서는 필요 없지만 트리 모양이 아닌 패턴일 경우)
        for (gap = input; gap > i; gap--) {
            printf(" ");
        }

        printf("\n");
    }
    return 0;
}
```

### 수정된 코드 설명:

1. **왼쪽 공백 (`gap--`)**:
   - `gap = input; gap > i; gap--`는 왼쪽 공백을 차례대로 줄여나갑니다. 입력한 `input` 값을 기준으로 공백을 점점 줄여 나가며, 삼각형의 왼쪽 공백을 만들어 줍니다.

2. **별 출력**:
   - 별은 각 줄마다 `2 * i - 1`개의 별을 출력합니다. 첫 줄에 1개, 두 번째 줄에 3개, 세 번째 줄에 5개 등, 규칙적으로 별의 개수가 증가합니다.

3. **우측 공백 출력 (선택)**:
   - 우측에 공백이 필요하지 않다면 생략해도 됩니다. 하지만 만약 양쪽에 공백을 넣고 싶다면, 공백을 추가할 수 있습니다. 트리 모양에서는 필요 없지만, 다른 모양을 만들고 싶을 때 우측 공백이 필요할 수 있습니다.

### 결과 예시 (`n = 4`):
```
   *
  ***
 *****
*******
```

이제 `gap--`로도 트리 모양을 만들 수 있습니다. **우측 공백**은 사실 트리 모양에서는 굳이 필요 없을 수 있지만, 패턴이 좌우 대칭이 되게 하려면 양쪽에서 공백을 관리하는 방식도 있습니다.

더 실험해보고 싶은 것이 있거나 궁금한 점 있으면 언제든 물어봐 주세요! 😊
 



헛. 좀 더 수고스러움은 있지만 만들 수 있었다. 캬
 
근데 또 재밌는 실험했다.
 
만약 별 출력보다 오른쪽 공백출력을 먼저 컴파일하게 해버리면 어떻게 될까
 
그래도 왼쪽 공백 오른쪽 공백 나오지않을까. 공백들이 나와버리면 별이 그 뒤에 자리를 잡지않을까(?) 라고 
잠깐 생각하고 실행해보았다. 
 
 

 

gpt야 도와줘..

 
 
 
gpt:
지금 코드에서는 공백과 별을 출력하는 순서가 문제를 일으키고 있습니다. 이 코드의 흐름을 보면, 먼저 **왼쪽 공백**을 출력하고, 바로 이어서 **우측 공백**을 출력하고, 그 후에 **별**을 출력하는 방식인데, 이 방식에서는 우측 공백이 별을 출력하기 전에 삽입되므로 **우측 공백이 별에 의해 덮여서 보이지 않게 됩니다**.

### 왜 우측 공백이 제대로 보이지 않나요?

삼각형의 패턴에서, **별이 공백을 덮어 쓰기 때문**입니다. 우측 공백을 별보다 먼저 출력하고 별을 출력하면, 별이 공백을 차지하게 되어 우측 공백이 사라져 보입니다. 이는 화면에 출력되는 순서가 영향을 미치는 것이죠.

### 삼각형(트리) 모양에서의 기본 원리:
트리 모양을 만들 때는 별을 가운데 정렬시키기 위해 **왼쪽에 공백**을 출력하고, 그 다음에 **별**을 출력한 후, 우측 공백이 필요할 경우 추가하면 됩니다. 하지만 트리 모양의 패턴에서는 별이 모두 차지하게 되므로 보통 우측 공백은 필요하지 않습니다.

### 올바른 순서로 공백과 별 출력하기
우측 공백이 별에 가려서 보이지 않는 이유는 공백을 출력한 후 별이 출력되기 때문입니다. 별을 출력하고 나서 우측 공백을 추가하려면 아래와 같은 순서로 코드를 수정해야 합니다.

#### 우측 공백이 필요 없다면:
일반적인 트리 모양에서는 우측 공백이 필요하지 않으므로, 다음과 같이 **왼쪽 공백 → 별 출력** 순서로 처리하면 됩니다.

```c
#include <stdio.h>
int main() {
    int i, j, input, gap;

    printf("몇 줄 짜리 삼각형? : ");
    scanf_s("%d", &input);

    for (i = 1; i <= input; i++) {
        // 왼쪽 공백 출력
        for (gap = input; gap > i; gap--) {
            printf(" ");
        }

        // 별 출력
        for (j = 1; j <= (2 * i - 1); j++) {
            printf("*");
        }

        printf("\n");
    }
    return 0;
}
```

### 우측 공백을 별 뒤에 출력하려면:

우측 공백이 필요하다고 가정하면, **별을 출력한 후** 우측 공백을 출력하는 방식으로 순서를 조정해야 합니다.

```c
#include <stdio.h>
int main() {
    int i, j, input, gap;

    printf("몇 줄 짜리 삼각형? : ");
    scanf_s("%d", &input);

    for (i = 1; i <= input; i++) {
        // 왼쪽 공백 출력
        for (gap = input; gap > i; gap--) {
            printf(" ");
        }

        // 별 출력
        for (j = 1; j <= (2 * i - 1); j++) {
            printf("*");
        }

        // 우측 공백 출력
        for (gap = input; gap > i; gap--) {
            printf(" ");
        }

        printf("\n");
    }
    return 0;
}
```

### 결과 (입력: `4`):

```
   *    
  ***   
 *****  
*******
```

여기서 보듯이, 우측 공백을 별 뒤에 넣으면 공백이 별 옆에 나타나는 형태가 됩니다. 다만, 트리 모양에서는 주로 **왼쪽 공백**만 출력하고 우측 공백은 넣지 않는 경우가 많습니다.

혹시 더 궁금한 점이 있으면 언제든지 질문해 주세요! 😊

 



 
하핫. 덮어씌워버리는거였다. 이런 이런 별 친구 개성이 너무 강하다구~
 

곧 크리스마스가 다가온다. c언어 별 트리는 어떤지.... 올해도 벌써 끝이 다가오는구나.. 시간 참 빠르다..

 

결론

 

 
for문의 사용 이유를 알면 다중 for문의 이해가 좀 더 직관적으로 변하는 것 같다.


01234
 늘 고마운 내 친구 지피티.. !!

 

'Study > C Language' 카테고리의 다른 글

씹어먹는 C언어 혼자 실습 (3) switch문  (1) 2024.10.17
씹어먹는 C언어 혼자 실습 (1)  (1) 2024.10.16