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`가 증가할수록 출력하는 공백의 수는 줄어들게 되어, 별이 **가운데 정렬된 삼각형** 모양을 만들게 됩니다.
혹시 더 궁금한 부분 있으면 알려주세요!
나:
(내가 이해 안됐던 부분)
그렇게
밥시간이 다되서 밥 먹으러 갔다.
뼈다귀해장국 저녁으로 먹으러 가서 주문하고 기다리는 동안 이 블로그 글을 읽고있다가
깨달았다.
https://m.post.naver.com/viewer/postView.nhn?volumeNo=8390558&memberNo=1991839
아
값이 줄지만
반복 횟수는 늘고있었다
그래서 증가였다.
수학적인 개념에서 내가 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:
지금 코드에서는 공백과 별을 출력하는 순서가 문제를 일으키고 있습니다. 이 코드의 흐름을 보면, 먼저 **왼쪽 공백**을 출력하고, 바로 이어서 **우측 공백**을 출력하고, 그 후에 **별**을 출력하는 방식인데, 이 방식에서는 우측 공백이 별을 출력하기 전에 삽입되므로 **우측 공백이 별에 의해 덮여서 보이지 않게 됩니다**.
### 왜 우측 공백이 제대로 보이지 않나요?
삼각형의 패턴에서, **별이 공백을 덮어 쓰기 때문**입니다. 우측 공백을 별보다 먼저 출력하고 별을 출력하면, 별이 공백을 차지하게 되어 우측 공백이 사라져 보입니다. 이는 화면에 출력되는 순서가 영향을 미치는 것이죠.
### 삼각형(트리) 모양에서의 기본 원리:
트리 모양을 만들 때는 별을 가운데 정렬시키기 위해 **왼쪽에 공백**을 출력하고, 그 다음에 **별**을 출력한 후, 우측 공백이 필요할 경우 추가하면 됩니다. 하지만 트리 모양의 패턴에서는 별이 모두 차지하게 되므로 보통 우측 공백은 필요하지 않습니다.
### 올바른 순서로 공백과 별 출력하기
우측 공백이 별에 가려서 보이지 않는 이유는 공백을 출력한 후 별이 출력되기 때문입니다. 별을 출력하고 나서 우측 공백을 추가하려면 아래와 같은 순서로 코드를 수정해야 합니다.
#### 우측 공백이 필요 없다면:
일반적인 트리 모양에서는 우측 공백이 필요하지 않으므로, 다음과 같이 **왼쪽 공백 → 별 출력** 순서로 처리하면 됩니다.
```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`):
```
*
***
*****
*******
```
여기서 보듯이, 우측 공백을 별 뒤에 넣으면 공백이 별 옆에 나타나는 형태가 됩니다. 다만, 트리 모양에서는 주로 **왼쪽 공백**만 출력하고 우측 공백은 넣지 않는 경우가 많습니다.
혹시 더 궁금한 점이 있으면 언제든지 질문해 주세요! 😊
하핫. 덮어씌워버리는거였다. 이런 이런 별 친구 개성이 너무 강하다구~
결론
for문의 사용 이유를 알면 다중 for문의 이해가 좀 더 직관적으로 변하는 것 같다.
'Study > C Language' 카테고리의 다른 글
씹어먹는 C언어 혼자 실습 (3) switch문 (1) | 2024.10.17 |
---|---|
씹어먹는 C언어 혼자 실습 (1) (1) | 2024.10.16 |