반복문 for

C언어에는 여러 반복문이 존재합니다. for문, while문, do ~ while문이 있지요. 오늘은 가장 흔하게 쓰이는 for문에 대하여 이야기해보도록 하겠습니다. 

for문에 대한 형식은 일반적으로 아래와 같은 형태입니다.

1. 초기화 식이 먼저 수행됩니다. 이는 for문 최초 1회만 수행됩니다.

2. 이후 조건식을 보고 true이며 for문 내부에 있는 코드를 수행하고, false이면 for문을 멈추고 빠져나옵니다.

3. 조건식이 참일 경우 수행되는 내부 부분입니다.

4. 이후 증감식을 수행한 후 다시 2의 조건식에 맞는지 확인합니다. 

이후 2 ~ 4의 반복입니다.

 

예 ) 1~10까지의 합

이러한 기본 형식을 지킨 1부터 10까지 모두 더한 수를 구한 예제입니다.

#include <stdio.h>

void main() {
	int i;
	int sum = 0;
	for (i = 1; i <=10; i++) {
		sum += i;
	}
	printf("1부터 10까지의 합 : %d\n", sum);
}

 

중첩 for문 

for문안에 for문이 등장하여 중복적으로 반복문을 수행할 수도 있습니다. 이를 중첩 for문, 혹은 2중 for문이라고 합니다. 원리는 간단합니다. 수행 부분이 내부 for문으로 바뀌는 거거든요. 아래는 이와 관련된 구구단의 예제입니다.

int i, j;
for (int i = 2; i <= 9; i++) {
	for (int j = 1; j <= 9; j++) {
		printf("%d * %d = %d\n", i, j, i * j);
	}
	printf("\n");
}

 

for문의 제어 - continue, break 

상황에 따라서 이번 수행부분은 건너뛰거나, 아예 for문을 멈춰야하는 상황이 발생할 수 있습니다. 이럴 경우 쓰이는 키워드가 if와 함께 continue와 break입니다.

continue : 이후 for문의 실행부분을 건너뜁니다.

break : break가 있는 for문을 종료시킵니다. 2중 for문의 경우 break가 등장하는 for문을 멈춰버립니다.

예 ) 1~10까지 짝수만 출력

for (int i = 1; i<=10; i++) {
	if (i % 2 == 1) continue;
	printf("%d \n", i);
}

 

예) 특정수와 일치하는 배열의 index 찾기

void main() {
	
	int numbers[] = { 5,4,2,1,9,11 };
	int found_index = -1;
	for (int i = 1; i<sizeof(numbers); i++) {
		if (numbers[i] == 9) {
			found_index = i;
			break;
		}
	}
	if (found_index != -1) {
		printf("9의 배열 index:%d\n", found_index);
	}
	else {
		printf("9를 찾을 수 없음\n");
	}
}

 

for문의 다양한 사용법 

for문은 일반적으로 이런식으로 사용한다는 것을 보여드렸습니다. 초기화식, 조건식, 증감식은 모두 생략이 가능합니다. 아래와 같이 다양하게 사용할 수 있습니다.

for(;;) // 무한 루프
for(i=1;;) //무한 루프
for(;i<5;i++) //초기화 구문 생략
for(;;i++)	//i가 1씩 증가하는 무한루프
for(i=1,j=1;;i++,j++)	//두가지 변수를 ,로 동시에 증감이 가능

 

for문 활용 - 별 출력

for문의 가장 대표적인 예제로는 별찍기가 있는데요. 한번 풀어보도록 합시다. 처음 몇개는 쉬우니까 우선 풀이는 생략하고 코드만 올리도록 하겠습니다.

1. 

*
**
***
****

아래는 코드입니다.

void main() {
	printf("*\n");
	printf("**\n");
	printf("***\n");
	printf("****\n");
}

장난이구요. 

void main() {
	int i, j;
	for (i = 1; i <= 4; i++) {
		for (j = 1; j <= i; j++)
			printf("*");
		printf("\n");
	}
}

 

2.

****
***
**
*
void main() {
	int i,j;
	for (i = 4; i > 0; i--) {
		for (j = 1; j <= i; j++)
			printf("*");
		printf("\n");
	}
}

 

3. 

   * 
  ***
 *****
*******

여기서부터 좀 많이 헤메실수 있어서 풀이방법도 기재해드립니다. 우선 코드분석해보시고 풀이를 봐주세요.

#include <stdio.h>

void main() {
	int i, j, height;
	scanf("%d", &height);
	for (i = 1; i <= height; i++) {
		for (j = 1; j <= height - i; j++) //공백 먼저 출력
			printf(" ");
		
		for (j = 1; j <= i * 2 - 1; j++)  //*출력
			printf("*");
		printf("\n");
	}
}

 

우선 i는 *과 공백을 포함한 한 줄을 의미합니다. 공백과 별을 어떻게 출력하는지는 아래와 같은 규칙을 갖게 됩니다. 아래의 그림은 높이가 4인 삼각형 모양의 별을 나타내었습니다.

i가 1일 경우 ) 우선 공백이 3개 출력되고, 별이 1개 출력이 됩니다.

i가 2일 경우 ) 공백이 2개 출력되고, 별이 3개 출력됩니다.

i가 3일 경우 ) 공백이 1개, 별이 5개 출력됩니다.

i가 4일 경우 ) 공백이 0개, 별이 7개 출력됩니다.

자, 이제 일반화하게 되면, 아래와 같은 규칙을 얻게 되지요.

공백 : height - i 까지 출력

별 : i*2 -1까지 출력

그래서 위의 코드와 같이 쓸 수 있습니다.

4.

*******
 *****
  ***
   *

이거는 i를 처음부터 height값으로 놓고 --i로 거꾸로 돌리면 됩니다.

void main() {
	int i, j, height;
	scanf("%d", &height);
	for (i = height; i >= 0; i--) {
		for (j = 1; j <= height - i; j++) //공백 먼저 출력
			printf(" ");
		
		for (j = 1; j <= i * 2 - 1; j++)  //*출력
			printf("*");
		printf("\n");
	}
}

 

4.

   *
  ***
 *****
*******
 *****
  ***
   *

 

위의 두 코드를 합치면 되는데, 중간에 같은줄이 두개 나오기 때문에 밑에는 height -1로 하여 한번 빼줍시다.

	for (i = 1; i <= height; i++) {
		for (j = 1; j <= height - i; j++) //공백 먼저 출력
			printf(" ");

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

	for (i = height-1; i >= 0; i--) {
		for (j = 1; j <= height - i; j++) //공백 먼저 출력
			printf(" ");

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

 

이상으로 별까지 출력하는 코드로 for문을 활용해보았습니다. for문은 배열과 같이 많이 쓰이기 때문에 반드시 알아야하는 반복문입니다.

반응형
블로그 이미지

REAKWON

와나진짜

,

 

더 많은 정보를 담은 리눅스 교재를 배포했습니다. 아래의 페이지에서 리눅스 교재를 받아가세요.

https://reakwon.tistory.com/233

 

리눅스 프로그래밍 note 배포

티스토리에 리눅스에 관한 내용을 두서없이 여지껏 포스팅했었데요. 저도 제 포스팅을 찾기가 어렵기도 하고 티스토리에서 코드삽입을 하게 되면 이게 일자로 쭉 쓰여져있는 x같은 현상이 생겨

reakwon.tistory.com

쉘스크립트 기본

쉘 스크립트는 쉘에게 무슨 명령들을 실행할지 알려주는 스크립트 파일입니다. 여기서는 가장 널리쓰이는 bash 쉘을 사용하는 스크립트를 설명하도록 하겠습니다.

#!/bin/bash

스크립트 최상단에는 항상 이 구문이 적혀있어야합니다. 간단하게 hello,world라는 문자열을 출력하는 스크립트를 만들어봅시다. 파일명은 exam.sh로 정해놓고요.

#!/bin/bash

echo "hello, world"
printf "hello, world"

 

./exam.sh로 스크립트를 실행하면 되는데 혹시 실행이 되지 않는다면 실행 권한이 없어서 그런것이니까 chmod 777 exam.sh로 권한을 바꾸어주면 됩니다. 그 후 결과를 보면 echo는 개행이 되지만 printf는 개행이 되지 않는 다는 것을 알 수 있습니다. 또 C언어 처럼 문자열을 전달할 수도 있는데 포맷 문자 %s를 이용하면 됩니다.

printf "%s, %s" hello, world

 

1) 변수(Variable)

쉘스크립트에서도 변수를 사용할 수 있는데요. 변수명=값 으로 변수를 선언하고, 사용할때는 앞에 $를 붙여줍니다. 중괄호를 이용하는 방법도 있습니다. ${변수}식으로 중괄호로 묶어서 사용합니다.

#!/bin/bash

h="hello"
w="world"
echo "${h}, ${w}"

 

여기서 export를 사용하여 다른 쉘 스크립트에서 사용할 수 있게 합니다. exam.sh는 변수 선언하고 export를, exam2.sh는 그 변수를 출력하는 쉘 스크립트입니다.

#!/bin/bash
#exam.sh
export MY_VAR="reakwon"

./exam2.sh

 

#!/bin/bash
#exam2.sh
echo ${MY_VAR}

 

매개변수

프로그램에서도 실행할때 인자를 주듯 쉘 스크립트도 역시 그렇게 할 수 있습니다. 실행한 스크립트 이름은 ${0}, 그 이후는 전달받은 인자 값들입니다(${1}, ${2}, ...). 아래의 예제코드를 보면서 이해하실 수 있습니다.

#!/bin/bash


echo "script name:${0}"
echo "매개변수 갯수 :${#}"
echo "전체 매개변수  값 : ${*}"
echo "전체 매개변수 값2 : ${@}"
echo "매개변수 1 : ${1}"
echo "매개변수 2 : ${2}"

 

 

 

 

 

 

 

 

예약변수

쉘 스크립트에서 사용자가 정해서 만들 수 없는 이미 정의된 변수가 존재합니다. 그것을 예약 변수라고 하는데요. 몇가지 예약 변수를 보도록 합시다.

변수 설명
HOME 사용자 홈 디렉토리를 의미합니다.
PATH 실행 파일의 경로입니다. 여러분이 chmod, mkdir 등의 명령어들은 /bin이나 /usr/bin, /sbin에 위치하는데, 이 경로들을 PATH 지정하면 여러분들은 굳이 /bin/chmod를 입력하지 않고, chmod 입력만 해주면 됩니다.
LANG 프로그램 실행 시 지원되는 언어를 말합니다.
UID 사용자의 UID입니다.
SHELL 사용자가 로그인시 실행되는 쉘을 말합니다.
USER 사용자의 계정 이름을 말합니다.
FUNCNAME 현재 실행되고 있는 함수 이름을 말합니다.
TERM 로그인 터미널을 말합니다.

 

2) 배열(Array)

쉘 스크립트에서 배열은 1차원 배열만 지원하며 중괄호를 사용해야합니다. 배열 원소는 소괄호안에 공백으로 구분하여 줍니다. 배열 안 원소는 문자열이든 정수든 상관 없이 쓸 수 있는 특징이 있습니다.

#!/bin/bash

arr=("hello" "world" 1 2 3 4 5)

echo "배열 전체 : ${arr[@]}"
echo "배열 원소의 갯수 : ${#arr[@]}"
echo "배열 첫번째 : ${arr}, 혹은 ${arr[0]}"
echo "5번 index를 갖는 배열의 원소 : ${arr[5]}"

arr[5]="five"

echo "5번 index를 갖는 배열의 원소 : ${arr[5]}"

# 5번 원소 해제
unset arr[5]
echo "5번 원소 삭제 후"
echo "5번 index를 갖는 배열의 원소 : ${arr[5]}"
echo "6번 index를 갖는 배열의 원소 : ${arr[6]}"

 

3) 함수(Function)

다른 프로그래밍 언어와 같이 쉘 스크립트에서도 함수를 사용할 수 있습니다. 함수의 정의 형식은 아래와 같습니다. 함수명 앞 function은 써주지 않아도 무관합니다. 주의 할 점은 함수가 호출되기 전에 함수가 정의되어 있어야하며 호출할때는 괄호를 써주지 않고 호출해야한다는 점입니다.

function 함수명(){
 ... 내용 ...
}
#!/bin/bash

function func(){
        echo "func()"
}

#함수 호출
func

 

4) 비교문

쉘스크립트에서 비교문은 약간 특이합니다. 아래와 같은 형식으로 비교문을 사용할 수 있습니다. 

if [ 값1 조건 값2 ]; then
	... 작업 내용 ...
fi

조건은 -eq, -gt, -lt 등이 있는데, 자세한 것은 아래의 코드에서 보도록 합시다.

#!/bin/bash

function func(){
        a=10
        b=5

        if [ ${a} -eq ${b} ]; then
                echo "a와 b는 같다."
        fi

        if [ ${a} -ne ${b} ]; then
                echo "a와 b는 같지 않다."
        fi

        if [ ${a} -gt ${b} ]; then
                echo "a가 b보다 크다."
        fi

        if [ ${a} -ge ${b} ]; then
                echo "a가 b보다 크거나 같다."
        fi

        if [ ${a} -lt ${b} ]; then
                echo "a가 b보다 작다."
        fi

        if [ ${a} -le ${b} ]; then
                echo "a가 b보다 작거나 같다."
        fi

}

#함수 호출
func

 

 

 

 

 

 

쉘스크립트는 명령어를 다루는 스크립트이기 때문에 파일이 존재하는지, 디렉토리가 존재하는지 등 파일과 관련된 조건 여부도 조건문을 통해 알 수 있습니다. 아래는 그것을 정리한 표입니다. 그리고 앞에 느낌표(!)를 써주고 조건을 기재하면 그 조건이 false일때 참이 성립합니다.

파일 관련 조건

조건 설명
if [ -d ${변수} ]; then 
if [ ! -d ${변수} ]; then
${변수}의 디렉토리가 존재하면 참이 성립합니다. 
${변수}의 디렉토리가 존재하지 않으면 참이 성립합니다. 
if [ -e ${변수} ]; then 
if [ ! -e ${변수} ]; then 
${변수}라는 파일이 존재하면 참입니다.
${변수}라는 파일이 존재하지 않으면 참입니다.
if [ -L ${변수} ]; then 파일이 symbolic link이면 참입니다.
if [ -s ${변수} ]; then 파일의 크기가 0보다 크면 참입니다.
if [ -S ${변수} ]; then 파일 타입이 소켓이면 참입니다.
if [ -r ${변수} ]; then 파일을 읽을 수 있으면 참입니다.
if [ -w ${변수} ]; then 파일을 쓸 수 있으면 참입니다.
if [ -x ${변수} ]; then 파일을 실행할 수 있으면 참입니다.
if [ -f ${변수} ]; then 파일이 정규 파일이면 참입니다.
if [ -c ${변수} ]; then 파일이 문자 장치이면 참입니다.
if [ ${변수1} -nt ${변수2}]; then 변수1의 파일이 변수2의 파일보다 최신 파일이면 참입니다.
if [ ${변수1} -ot ${변수2}]; then 변수1의 파일이 변수2의 파일보다 최신이 아니면 참입니다.
if [ ${변수1} -ef ${변수2}]; then 변수1의 파일과 변수2의 파일이 동일하면 참입니다.

 

만약 AND조건과 OR조건을 섞어서 쓴다면 어떻게 할까요? AND는 -a, OR은 -o를 이용해서 조건을 추가할 수 있습니다.

function func(){
        a=aa
        b=bb
        if [ -f ${a} -a -d ${b} ]; then
                echo "a는 파일이고 b는 디렉토리 "
        fi
}

#함수 호출
func

 

또한 여러 조건을 걸려면, 즉, C언어에서 else if역할을 하는 것은 elif라는 것을 사용하여 else if와 똑같은 역할을 할 수 있게 해줍니다. elif[ 조건 ]; then 이런식으로 쓰시면 됩니다.

만약 반복문에서 사용하여 조건이 참일때 반복문을 멈추고 싶을때 break라는 키워드를 사용하여 반복문을 멈출 수 있습니다.

C에서 switch case와 동일한 구문을 하는 문법도 존재합니다. 아래와 같이 case문을 사용하면 됩니다. 각 case의 끝을 보면 세미콜론 2개로 종료하는 것을 볼 수 있습니다.

#!/bin/bash

case ${1} in
        "linux") echo "리눅스" ;;
        "unix") echo "유닉스" ;;
        "windows") echo "윈도우즈" ;;
        "MacOS") echo "맥OS" ;;
        *) echo "머야" ;;
esac

5) 반복문

반복문 중 for문에 대한 설명은 예제와 같이 보는 것으로 하겠습니다. 

#!/bin/bash

function func(){
        echo "사용예1"
        for i in 1 2 3 4 5
        do
                echo "${i}"
        done

        echo "사용예2"
        list="1 2 3 4 5"
        for i in ${list}
        do
                echo "${i}"
        done

        echo "사용예3"
        for i in {1..5}
        do
                echo "${i}"
        done

        echo "사용예4: 크기를 2만큼 증가시키면서 출력"
        for i in {1..5..2}
        do
                echo "${i}"
        done

        echo "사용예5: 배열을 이용"
        arr=(1 2 3 4 5)
        for i in "${arr[@]}"
        do
                echo "${i}"
        done


        echo "사용예6: C와 유사한 형식의 for문"
        for ((i=0; i<5; i++)); do
                echo "${i}"
        done
}

#함수 호출
func

 

 

 

 

 

6) 명령어의 종료 코드(exit)

만약 명령어가 실패할 경우 동작을 다르게 할것이라면 어떻게 할까요? 명령어의 종료 코드를 얻어오면 됩니다. 명령어의 종료 코드는 $?에 가장 최근 실행한 명령어의 종료 코드가 있습니다. 정상적인 종료는 0이 반환되는데, 만약 0이 아닌 값으로 반환되면 오류라고 판단하시면 됩니다. 여기에 간단한 오류를 내는 c파일(main.c)을 작성하고 gcc로 컴파일(gcc main.c)합니다. 이 c파일은 실행시 전달인자가 2개 보다 작으면 exit으로 코드 16을 반환합니다.

#include <stdlib.h>
#include <stdio.h>
int main(int argc, char* argv[]){
        if(argc<2){
                fprintf(stderr,"인자는 2개 이상이어야 합니다.\n");
                exit(16);
        }
}

 

그리고 쉘스크립트를 아래와 같이 수정해서 오류의 코드가 얼마인지 확인해보면 우리가 exit에 넘겨준 16이 찍히는 것을 확인할 수 있습니다.

#!/bin/bash

function func(){
        ./a.out
        echo "오류 코드 ($?)"
}

#함수 호출
func

 

./a.out에 인자를 하나 넣어서 다시 실행시켜보세요. 0이 종료코드로 반환 될 것입니다. 이렇게 이전에 명령어의 결과를 봐야하는 경우 $?으로 판단하여 분기시킬 수 있습니다.

이렇게 종료 반환 코드는 명령어 뿐만 아니라 쉘 스크립트 자체도 반환할 수 있습니다. 즉, 쉘 스크립트의 수행이 실패했는지 알려주기 위해서는 exit 명령어를 사용하면 됩니다. 아래의 예가 그 사용법을 보여줍니다. 우선 exam2.sh라는 파일을 만들어봅시다. 이 쉘 스크립트 파일은 exam.sh에서 실행할 예정입니다. 별거없이 16의 종료코드를 반환하며 끝이 납니다. 

#!/bin/bash

exit 16

 

이 쉘 파일을 exam.sh에서 실행시켜볼까요?

#!/bin/bash

function func(){
        ./exam2.sh
        echo "오류 코드 ($?)"
}

#함수 호출
func

 

확인해보면 우리가 기재했던 16이 출력되는 것을 확인할 수 있습니다.

 

 

 

반응형
블로그 이미지

REAKWON

와나진짜

,