반복문 break문과 continue문
break
반복문 (여기선 while문) 내부에서 특정 조건이 되면 break를 만나게 되는데, break문은 반복문을 빠져나가게 된다.
#include <stdio.h>
int main()
{
int a = 0;
while(1){
if(a > 100){
break;
}
printf("a의 값은 %d입니다.\\n", a);
a++;
}
printf("a는 100보다 크다\\n");
return 0;
}
continue
반복문 while문 내부에서 특정 조건이 되면 continue문을 만나게 되는데, 이 때 continue문 이하의 수행은 무시하고, 다시 반복의 시작점(조건식)으로 간다.
for문에서는 증감식으로 이동
#include <stdio.h>
int main()
{
int a = 0;
while(a < 100){
a++;
if(a > 80 && a < 90){
continue;
}
printf("a의 값 : %d\\n", a);
}
// continu문 문제 1. 구구단을 출력하되, 짝수단만 출력
int a = 0;
while(a < 9){
a++;
if(a % 2 != 0){
continue;
}
int b = 1;
while(b < 10){
printf("%d * %d = %d\\n", a, b, a * b);
b++;
}
}
return 0;
}
함수
함수의 기본 헝태
- 데이터 타입(자료형) - 함수가 리턴하는 값의 타입
- 함수 이름 - 함수 기능과 밀접한 이름으로 만드는 것이 좋음
- 인수 목록 - 함수에 필요한 값을 전달할 때 사용 (=매개변수 = 전달인자 = 파라미터)
- 함수의 내용 - 중괄호 {} 사이의 영역 안에서 작성
자료형 함수이름(인수목록){
함수의 내용
}
#include <stdio.h>
// 함수
// 더하기 Add 기능 함수
int Add(int a, int b){
return a + b;
}
int main()
{
int i = 10;
int j = 20;
int hap = 0;
hap = Add(i, j);
printf("%d\\n", hap);
return 0;
}
void 타입
void = 타입이 없다라는 의미
결과값을 리턴하지 않는 함수 (= 결과값을 리턴할 게 없는 함수)
#include <stdio.h>
int Add(int a, int b);
void print_Start(){
printf("===== 프로그래밍 시작 =====\\n");
printf("두 개의 정수를 입력하시오 : ");
}
void print_Hap(int result){
printf("두 수의 합은 %d입니다. \\n", result);
printf("===== 프로그래밍 끝 =====\\n");
}
#include <stdio.h>
// 함수 문제 1. 사각형의 넓이를 구하는 함수 작성. 사용자로부터 두 정수(가로의 길이, 세로의 길이)를 각각 입력 받아 함수의 전달인자로 전달하고, 사각형의 넓이를 출력하는 함수를 작성. 그리고 이 함수를 Main에서 호출하여 출력.
void calcRectangle(int width, int height){
printf("사각형 넓이는 %d", width * height);
}
int main()
{
int widthInput , heightInput;
scanf("%d", &widthInput);
scanf("%d", &heightInput);
calcRectangle(widthInput, heightInput);
return 0;
}
#include <stdio.h>
// 함수 문제 2. 사용자로부터 두 수를 입력받아, 두 수를 비교하여 최대값과 최소값을 구하는 함수를 정의. 그리고 main함수에서 이 함수를 호출하여 결과값을 출력
void compare(int a, int b){
if(a > b){
printf("최대값 : %d\\n", a);
printf("최소값 : %d\\n", b);
}else{
printf("최대값 : %d\\n", b);
printf("최소값 : %d\\n", a);
}
}
int main (){
int a , b;
printf("두 정수를 입력하시오 : ");
scanf("%d %d", &a, &b);
compare(a, b);
return 0;
}
#include <stdio.h>
/* 함수 문제 3.
커피 자판기가 있다.
100원 넣으면 '블랙커피',
200원 넣으면 '밀크커피'가 나온다.
자판기가 함수와 같은 블랙박스라고 했었다.
자판기를 함수로 구현.
즉, 사용자로부터 정수형 가격(100, 200)을 받아
100을 입력 받으면 -> 블랙커피
200을 입력 받으면 -> 밀크커피
*/
void coffeeMachine(int money){
if(money == 100){
printf("블랙커피");
}else if(money == 200){
printf("밀크커피");
}
}
int main (){
int money;
scanf("%d", &money);
coffeeMachine(money);
return 0;
}
변수의 범위
지역변수
- 변수가 선언된 블록 내에서만 유효하며, 블록이 종료되면 메모리에서 사라진다
- 함수 호출 순서와 소멸 순서는 반대이다.
- 함수의 매개변수도 스택 메모리에 할당되는 지역변수이다.
- 메모리상의 스택(stack) 영역에 저장되며, 초기화하지 않으면 의미 없는 값(쓰레기값)으로 초기화된다
- 블록 내에 선언된 변수
전역변수
- 프로그램의 어디에서나 접근할 수 있다메모리상의 데이터(data) 영역에 저장되며, 직접 초기화하지 않아도 0으로 자동 초기화된다
- 프로그램이 시작하자마자 (데이터)메모리 상에 올라가서 프로그램이 종료될 때 메모리 상에서 소멸된다
- 함수 바깥쪽에 선언된 변수
static 변수
- 지역변수와 전역변수 반반 섞은 느낌
- 지역변수처럼 중괄호 영역에서 선언되지만, 중괄호를 벗어나도 (데이터)메모리상에 고정되어 소멸하지 않는다.
- 언제 소멸되나? 전역변수와 동일하게 프로그램이 종료될 때 메모리 상에서 소멸한다. 왜냐하면 전역변수처럼 데이터 영역에서 관리되기때문이다.
- 함수 내에서 선언된 정적 변수는 전역 변수처럼 단 한 번만 초기화(초기화는 최초 실행 시 단 한번만 수행됨)
- 또한, 이렇게 선언된 정적 변수는 지역 변수처럼 해당 함수 내에서만 접근할 수 있다
#include <stdio.h>
void func(){
static int value = 0;
value++;
printf("%d\\n", value)
;}
int main (){
int i = 0;
while(i < 5){
func();
i++;
}
return 0;
}
// 결과 값은 1 2 3 4 5 로 나온다.
배열
1. 배열 선언 구조
- 배열의 타입 : 배열 요소들의 타입을 나타낸다
- 배열 이름 : 각 배열 요소에 접근하기 위해 배열 이름을 나타낸다
- 배열 길이 : 변수의 개수를 나타낸다
- int array[5] - 배열의 타입 : int, 배열 이름 : array, 길이 : 5
//배열 타입: int, 배열 이름: array, 길이: [5]
int array[5];
- 배열의 첫 번째 인덱스는 무조건 0부터 시작
- 배열의 초기화 형태 - int array[5] = {1, 2, 3, 4, 5}
//배열의 초기화 형태
int array[5] = {1, 2, 3, 4, 5}
- 배열을 사용할 때 일반적으로 배열의 길이를 생략하고 많이 쓴다. 왜냐하면 실무에서는 배열에 들어가는 데이터가 어마무시하게 많기때문에 몇 개라고 정확하게 알기 어렵다. 일일이 데이터의 개수를 세서 배열의 길이를 지정하는 것은 비효율적이다.
- 그래서 배열의 길이를 생략하고 초기값을 넣어준다. 그러면 배열 길이를 지정하지 않아도 컴파일러가 알아서 배열의 길이를 계산해서 지정해준다.
int array[] = {1, 2, 3, 4, 5}
2. 배열의 복사
- 같은 타입의 변수끼리 복사가 가능
- 배열도 배열끼리 복사가 가능
- 다음과 같이 변수 복사하듯이 복사하면 에러 발생
int arr1[5] = {1, 2, 3, 4, 5};
int arr2[5];
arr2 = arr1;
error C2106 에러 : 배열은 상수이기때문에 대입 연산자를 통해 값을 넘겨 받을 수 없다.
배열의 이름 자체는 상수이다.
- 배열은 요소끼리 복사해야한다.
#include <stdio.h>
int main (){
int i;
int arr1[5] = {1,2,3,4,5};
int arr2[5];
for(i=0; i < 5; i++){
arr2[i] = arr1[i];
printf("%d\\n", arr2[i]);
}
return 0;
}
#include <stdio.h>
int main (){
/*문제 1. 배열 arr1의 값을 배열 arr2에 복사하되,
배열 요소를 역순으로 저장하도록 하고,
복사된 arr2의 요소값들을 출력하도록 하라.
*/
int i;
int arr1[5] = {1,2,3,4,5};
int arr2[5];
for(i=0; i < 5; i++){
int j = 4;
arr2[i] = arr1[j - i];
printf("%d\\n", arr2[i]);
}
return 0;
}
문자열 변수
- null 문자에 관하여
- 문자열 끝에는 null 문자가 반드시 추가된다.
char str[100] "Beautiful";
- null 문자가 왜 필요한가?
- 문자수는 9개, 배열 개수(길이)는 100개, 91개의 공간이 빈다.
- 91개의 공간에는 쓰레기 값으로 채워져있다.
- 사람은 문자와 쓰레기값을 구분하지만, 컴퓨터는 구분이 불가능하다.
- 컴퓨터가 문자열의 끝을 인식하기 위해 null을 표시한다.
- “Beautiful”의 공간은 9개가 아니라 null을 포함하여 10개이다.
#include <stdio.h>
int main (){
int i;
char str1[100] = "Beautiful";
for(i=0; i<10; i++){
printf("%c", str1[i]);
}
printf("\\n");
printf("str1 = %s\\n", str1);
return 0;
}
포인터
#include <stdio.h>
int main (){
int b = 100;
int *pB = &b; // *는 포인터변수임을 알려주는 기호일뿐이다. 일반 변수와 구분하기 위함.
printf("b = %d\\n", b);
printf("&b = %p\\n", &b); //&b = 0x7ffcbfdef4fc (&p는 16진수로 표현)
printf("pB = %p\\n", pB); //pB = 0x7ffde10afc5c
printf("*pB = %d\\n", *pB); //*pB = 100
return 0;
}
- int *pB에 있는 *pB와 printf에 있는 *pB의 *pB는 서로 다른 pB이다
- int *pB에 있는 *와 printf에 있는 *는 의미가 다르다.
- int *pB에 있는 * : 선언할때 pB가 포인터 변수임을 표시하기 위해 붙임
- 선언 이외에 사용되는 * : 가리키는 해당 메모리의 실제값을 참조하라는 의미
포인터와 배열
배열의 이름은 첫번재 요소의 주소값을 저장하는 포인터다.
포인터 즉, 주소값이라는 것은 다량의 데이터가 있을 때 일일이 그 데이터의 주소값을 가질 필요없고 다량의 데이터가 한 단위로 묶여서 첫번째 주소값만 대표성을 가짐. 그래서 첫번째 주소값만 저장하면 그 데이터 덩어리를 대표하는 것이다.
#include <stdio.h>
int main ()
{
int arr[] = {1, 2, 3, 4, 5}; //배열 선언
for(int i = 0; i < 5; i++){
printf("%d\\n", arr[i]);
printf("%p\\n", &arr[i]);
/*
1
0x7ffd45667420
2
0x7ffd45667424
3
0x7ffd45667428
4
0x7ffd4566742c
5
0x7ffd45667430
*/
}
printf("배열의 이름 : %p\\n", arr); //배열의 이름 : 0x7ffd45667420
return 0;
}
배열의 이름 === 포인터(주소값)
배열의 이름이 포인터이지만 일반 포인터와 결정적인 차이점이 있다??
#include <stdio.h>
int main ()
{
int arr[] = {1, 2, 3, 4, 5};
int temp = 10;
arr = temp; //오류 발생
return 0;
}
temp의 값을 arr이라는 배열의 이름(or 배열)에 대입하려고 시도했지만 오류 발생
→ why? 배열의 이름은 상수이다. 즉, 배열은 포인터 상수이다. 상수를 가르키는 포인터를 의미. 상수라는 것은 값을 변경할 수 없다는 것을 의미한다.
⇒ 배열의 이름은 주소값을 갖는 포인터이지만 상수이므로 주소값을 변경할 수 없다.
함수와 포인터
- 함수의 매개변수를 전달하는 형태는 값에 의한 복사와 참조에 의한 복사가 있다.
- 기본적인 함수의 매개변수 전달 형태는 값에 의한 복사이다.
배열형의 인자는 포인터형으로 받는다.
- 1-5개 정도까지는 전달인자로 사용할 수 있다. 하지만 그 이상 사용하면 난잡해보임
- 배열을 전달인자로 사용하면 여러 개의 값을 넘길 수 있다.
- 어떻게 배열을 전달하고 받을 것인가? 바로 포인터!
int main()
{
Temp(arr);
}
매개변수 배열 arr는 즉, 배열을 나타내는 arr라는 배열의 이름은 주소값이다.
주소값을 매개변수로 넘기면 매개변수를 받는 입장에서는 주소값을 무엇으로 받아서 메모리에 저장할 수 있는가? → “포인터”로 배열의 주소를 받으면 됨
—> 주소값이 복사가 되고 있는 것이다. ⇒ 참조에 의한 복사
#include <stdio.h>
void func(int *pArr){
for(int i = 0; i < 5; i++){
printf("함수 안의 배열 : %d\\n", *(pArr + i)); //pArr + 1 == pArr[i]
}
}
int main ()
{
int arr[] = {1, 2, 3, 4, 5};
func(arr);
for(int i = 0; i < 5; i++){
printf("%d\\n", arr[i]);
}
return 0;
}
반복문 break문과 continue문
break
반복문 (여기선 while문) 내부에서 특정 조건이 되면 break를 만나게 되는데, break문은 반복문을 빠져나가게 된다.
#include <stdio.h>
int main()
{
int a = 0;
while(1){
if(a > 100){
break;
}
printf("a의 값은 %d입니다.\\n", a);
a++;
}
printf("a는 100보다 크다\\n");
return 0;
}
continue
반복문 while문 내부에서 특정 조건이 되면 continue문을 만나게 되는데, 이 때 continue문 이하의 수행은 무시하고, 다시 반복의 시작점(조건식)으로 간다.
for문에서는 증감식으로 이동
#include <stdio.h>
int main()
{
int a = 0;
while(a < 100){
a++;
if(a > 80 && a < 90){
continue;
}
printf("a의 값 : %d\\n", a);
}
// continu문 문제 1. 구구단을 출력하되, 짝수단만 출력
int a = 0;
while(a < 9){
a++;
if(a % 2 != 0){
continue;
}
int b = 1;
while(b < 10){
printf("%d * %d = %d\\n", a, b, a * b);
b++;
}
}
return 0;
}
함수
함수의 기본 헝태
- 데이터 타입(자료형) - 함수가 리턴하는 값의 타입
- 함수 이름 - 함수 기능과 밀접한 이름으로 만드는 것이 좋음
- 인수 목록 - 함수에 필요한 값을 전달할 때 사용 (=매개변수 = 전달인자 = 파라미터)
- 함수의 내용 - 중괄호 {} 사이의 영역 안에서 작성
자료형 함수이름(인수목록){
함수의 내용
}
#include <stdio.h>
// 함수
// 더하기 Add 기능 함수
int Add(int a, int b){
return a + b;
}
int main()
{
int i = 10;
int j = 20;
int hap = 0;
hap = Add(i, j);
printf("%d\\n", hap);
return 0;
}
void 타입
void = 타입이 없다라는 의미
결과값을 리턴하지 않는 함수 (= 결과값을 리턴할 게 없는 함수)
#include <stdio.h>
int Add(int a, int b);
void print_Start(){
printf("===== 프로그래밍 시작 =====\\n");
printf("두 개의 정수를 입력하시오 : ");
}
void print_Hap(int result){
printf("두 수의 합은 %d입니다. \\n", result);
printf("===== 프로그래밍 끝 =====\\n");
}
#include <stdio.h>
// 함수 문제 1. 사각형의 넓이를 구하는 함수 작성. 사용자로부터 두 정수(가로의 길이, 세로의 길이)를 각각 입력 받아 함수의 전달인자로 전달하고, 사각형의 넓이를 출력하는 함수를 작성. 그리고 이 함수를 Main에서 호출하여 출력.
void calcRectangle(int width, int height){
printf("사각형 넓이는 %d", width * height);
}
int main()
{
int widthInput , heightInput;
scanf("%d", &widthInput);
scanf("%d", &heightInput);
calcRectangle(widthInput, heightInput);
return 0;
}
#include <stdio.h>
// 함수 문제 2. 사용자로부터 두 수를 입력받아, 두 수를 비교하여 최대값과 최소값을 구하는 함수를 정의. 그리고 main함수에서 이 함수를 호출하여 결과값을 출력
void compare(int a, int b){
if(a > b){
printf("최대값 : %d\\n", a);
printf("최소값 : %d\\n", b);
}else{
printf("최대값 : %d\\n", b);
printf("최소값 : %d\\n", a);
}
}
int main (){
int a , b;
printf("두 정수를 입력하시오 : ");
scanf("%d %d", &a, &b);
compare(a, b);
return 0;
}
#include <stdio.h>
/* 함수 문제 3.
커피 자판기가 있다.
100원 넣으면 '블랙커피',
200원 넣으면 '밀크커피'가 나온다.
자판기가 함수와 같은 블랙박스라고 했었다.
자판기를 함수로 구현.
즉, 사용자로부터 정수형 가격(100, 200)을 받아
100을 입력 받으면 -> 블랙커피
200을 입력 받으면 -> 밀크커피
*/
void coffeeMachine(int money){
if(money == 100){
printf("블랙커피");
}else if(money == 200){
printf("밀크커피");
}
}
int main (){
int money;
scanf("%d", &money);
coffeeMachine(money);
return 0;
}
변수의 범위
- 지역변수변수가 선언된 블록 내에서만 유효하며, 블록이 종료되면 메모리에서 사라진다
함수 호출 순서와 소멸 순서는 반대이다. - 함수의 매개변수도 스택 메모리에 할당되는 지역변수이다.

- 스택 메모리에 존재하는 시간 - 언제 생성되고 언제 소멸되는가?
- 메모리상의 스택(stack) 영역에 저장되며, 초기화하지 않으면 의미 없는 값(쓰레기값)으로 초기화된다
- 블록 내에 선언된 변수
- 전역변수프로그램의 어디에서나 접근할 수 있다메모리상의 데이터(data) 영역에 저장되며, 직접 초기화하지 않아도 0으로 자동 초기화된다
- 프로그램이 시작하자마자 (데이터)메모리 상에 올라가서 프로그램이 종료될 때 메모리 상에서 소멸된다
- 함수 바깥쪽에 선언된 변수
- static 변수지역변수처럼 중괄호 영역에서 선언되지만, 중괄호를 벗어나도 (데이터)메모리상에 고정되어 소멸하지 않는다.함수 내에서 선언된 정적 변수는 전역 변수처럼 단 한 번만 초기화(초기화는 최초 실행 시 단 한번만 수행됨)
#include <stdio.h> void func(){ static int value = 0; value++; printf("%d\\n", value) ;} int main (){ int i = 0; while(i < 5){ func(); i++; } return 0; } // 결과 값은 1 2 3 4 5 로 나온다.
그날 그날 읽은 책들의 페이지 수를 사용자로부터 입력 받으면 최종 누적된 페이지 수에 새로 입력된 페이지 수가 추가로 더해지고, 다시 갱신된 최종 페이지 수가 출력되는 것이다.이 기능을 함수로 구현하되, 페이지의 누적 결과를 저장하는 변수를 전역 변수로도 구현해보고, static 변수로도 구현해라. - #include <stdio.h> void calcPages(int cur){ static int acc = 0; acc += cur; printf("최종 누적 페이지 : %d\\n", acc); ;} int main (){ int cur = 0; while(1){ printf("읽은 책의 페이지 수를 입력하시오 : "); scanf("%d", &cur); if(cur == -1){ printf("더 분발하세요."); break; } calcPages(cur); } return 0; }
- 한번의 출력이 끝나면 다시 읽은 책의 페이지 수를 사용자로부터 입력받고, 누적된 최종 페이지 수를 출력한다. 이 과정을 사용자가 -1을 입력할 때까지 계속 반복한다.
- 책읽기 마라톤은 내가 읽은 책들의 페이지 수를 누적 계산하는 기능이다.
- 문제1. 책읽기 마라톤 기능 프로그램 구현
- 또한, 이렇게 선언된 정적 변수는 지역 변수처럼 해당 함수 내에서만 접근할 수 있다
- 언제 소멸되나? 전역변수와 동일하게 프로그램이 종료될 때 메모리 상에서 소멸한다. 왜냐하면 전역변수처럼 데이터 영역에서 관리되기때문이다.
- 지역변수와 전역변수 반반 섞은 느낌
배열
- 배열 선언 구조
- 배열의 타입 : 배열 요소들의 타입을 나타낸다
- 배열 이름 : 각 배열 요소에 접근하기 위해 배열 이름을 나타낸다
- 배열 길이 : 변수의 개수를 나타낸다
- int array[5] - 배열의 타입 : int, 배열 이름 : array, 길이 : 5
- 배열의 첫 번째 인덱스는 무조건 0부터 시작
- 배열의 초기화 형태 - int array[5] = {1, 2, 3, 4, 5}
- 배열을 사용할 때 일반적으로 배열의 길이를 생략하고 많이 쓴다. 왜냐하면 실무에서는 배열에 들어가는 데이터가 어마무시하게 많기때문에 몇 개라고 정확하게 알기 어렵다. 일일이 데이터의 개수를 세서 배열의 길이를 지정하는 것은 비효율적이다.
- 그래서 배열의 길이를 생략하고 초기값을 넣어준다. 그러면 배열 길이를 지정하지 않아도 컴파일러가 알아서 배열의 길이를 계산해서 지정해준다.
- 배열의 복사
- 같은 타입의 변수끼리 복사가 가능
- 배열도 배열끼리 복사가 가능
- 다음과 같이 변수 복사하듯이 복사하면 에러 발생
int arr1[5] = {1, 2, 3, 4, 5};
int arr2[5];
arr2 = arr1;
error C2106 에러 : 배열은 상수이기때문에 대입 연산자를 통해 값을 넘겨 받을 수 없다.
배열의 이름 자체는 상수이다.
- 배열은 요소끼리 복사해야한다.
#include <stdio.h>
int main (){
int i;
int arr1[5] = {1,2,3,4,5};
int arr2[5];
for(i=0; i < 5; i++){
arr2[i] = arr1[i];
printf("%d\\n", arr2[i]);
}
return 0;
}
#include <stdio.h>
int main (){
/*문제 1. 배열 arr1의 값을 배열 arr2에 복사하되,
배열 요소를 역순으로 저장하도록 하고,
복사된 arr2의 요소값들을 출력하도록 하라.
*/
int i;
int arr1[5] = {1,2,3,4,5};
int arr2[5];
for(i=0; i < 5; i++){
int j = 4;
arr2[i] = arr1[j - i];
printf("%d\\n", arr2[i]);
}
return 0;
}
문자열 변수
- null 문자에 관하여
- 문자열 끝에는 null 문자가 반드시 추가된다.
char str[100] "Beautiful";
- null 문자가 왜 필요한가?
- 문자수는 9개, 배열 개수(길이)는 100개, 91개의 공간이 빈다.
- 91개의 공간에는 쓰레기 값으로 채워져있다.
- 사람은 문자와 쓰레기값을 구분하지만, 컴퓨터는 구분이 불가능하다.
- 컴퓨터가 문자열의 끝을 인식하기 위해 null을 표시한다.
- “Beautiful”의 공간은 9개가 아니라 null을 포함하여 10개이다.
#include <stdio.h>
int main (){
int i;
char str1[100] = "Beautiful";
for(i=0; i<10; i++){
printf("%c", str1[i]);
}
printf("\\n");
printf("str1 = %s\\n", str1);
return 0;
}
포인터
#include <stdio.h>
int main (){
int b = 100;
int *pB = &b; // *는 포인터변수임을 알려주는 기호일뿐이다. 일반 변수와 구분하기 위함.
printf("b = %d\\n", b);
printf("&b = %p\\n", &b); //&b = 0x7ffcbfdef4fc (&p는 16진수로 표현)
printf("pB = %p\\n", pB); //pB = 0x7ffde10afc5c
printf("*pB = %d\\n", *pB); //*pB = 100
return 0;
}
- int *pB에 있는 *pB와 printf에 있는 *pB의 *pB는 서로 다른 pB이다
- int *pB에 있는 *와 printf에 있는 *는 의미가 다르다.
- int *pB에 있는 * : 선언할때 pB가 포인터 변수임을 표시하기 위해 붙임
- 선언 이외에 사용되는 * : 가리키는 해당 메모리의 실제값을 참조하라는 의미
포인터와 배열
배열의 이름은 첫번재 요소의 주소값을 저장하는 포인터다.
포인터 즉, 주소값이라는 것은 다량의 데이터가 있을 때 일일이 그 데이터의 주소값을 가질 필요없고 다량의 데이터가 한 단위로 묶여서 첫번째 주소값만 대표성을 가짐. 그래서 첫번째 주소값만 저장하면 그 데이터 덩어리를 대표하는 것이다.
#include <stdio.h>
int main ()
{
int arr[] = {1, 2, 3, 4, 5}; //배열 선언
for(int i = 0; i < 5; i++){
printf("%d\\n", arr[i]);
printf("%p\\n", &arr[i]);
/*
1
0x7ffd45667420
2
0x7ffd45667424
3
0x7ffd45667428
4
0x7ffd4566742c
5
0x7ffd45667430
*/
}
printf("배열의 이름 : %p\\n", arr); //배열의 이름 : 0x7ffd45667420
return 0;
}
배열의 이름 === 포인터(주소값)
배열의 이름이 포인터이지만 일반 포인터와 결정적인 차이점이 있다??
#include <stdio.h>
int main ()
{
int arr[] = {1, 2, 3, 4, 5};
int temp = 10;
arr = temp; //오류 발생
return 0;
}
temp의 값을 arr이라는 배열의 이름(or 배열)에 대입하려고 시도했지만 오류 발생
→ why? 배열의 이름은 상수이다. 즉, 배열은 포인터 상수이다. 상수를 가르키는 포인터를 의미. 상수라는 것은 값을 변경할 수 없다는 것을 의미한다.
⇒ 배열의 이름은 주소값을 갖는 포인터이지만 상수이므로 주소값을 변경할 수 없다.
함수와 포인터
- 함수의 매개변수를 전달하는 형태는 값에 의한 복사와 참조에 의한 복사가 있다.
- 기본적인 함수의 매개변수 전달 형태는 값에 의한 복사이다.
a와 b는 각각의 메모리를 가지고 있고 값만 복사가 되는 것이다.
배열형의 인자는 포인터형으로 받는다.
- 1-5개 정도까지는 전달인자로 사용할 수 있다. 하지만 그 이상 사용하면 난잡해보임
- 배열을 전달인자로 사용하면 여러 개의 값을 넘길 수 있다.
- 어떻게 배열을 전달하고 받을 것인가? 바로 포인터!
int main()
{
Temp(arr);
}
매개변수 배열 arr는 즉, 배열을 나타내는 arr라는 배열의 이름은 주소값이다.
주소값을 매개변수로 넘기면 매개변수를 받는 입장에서는 주소값을 무엇으로 받아서 메모리에 저장할 수 있는가? → “포인터”로 배열의 주소를 받으면 됨
—> 주소값이 복사가 되고 있는 것이다. ⇒ 참조에 의한 복사
#include <stdio.h>
void func(int *pArr){
for(int i = 0; i < 5; i++){
printf("함수 안의 배열 : %d\\n", *(pArr + i)); //pArr + 1 == pArr[i]
}
}
int main ()
{
int arr[] = {1, 2, 3, 4, 5};
func(arr);
for(int i = 0; i < 5; i++){
printf("%d\\n", arr[i]);
}
return 0;
}
반복문 break문과 continue문
break
반복문 (여기선 while문) 내부에서 특정 조건이 되면 break를 만나게 되는데, break문은 반복문을 빠져나가게 된다.
#include <stdio.h>
int main()
{
int a = 0;
while(1){
if(a > 100){
break;
}
printf("a의 값은 %d입니다.\\n", a);
a++;
}
printf("a는 100보다 크다\\n");
return 0;
}
continue
반복문 while문 내부에서 특정 조건이 되면 continue문을 만나게 되는데, 이 때 continue문 이하의 수행은 무시하고, 다시 반복의 시작점(조건식)으로 간다.
for문에서는 증감식으로 이동
#include <stdio.h>
int main()
{
int a = 0;
while(a < 100){
a++;
if(a > 80 && a < 90){
continue;
}
printf("a의 값 : %d\\n", a);
}
// continu문 문제 1. 구구단을 출력하되, 짝수단만 출력
int a = 0;
while(a < 9){
a++;
if(a % 2 != 0){
continue;
}
int b = 1;
while(b < 10){
printf("%d * %d = %d\\n", a, b, a * b);
b++;
}
}
return 0;
}
함수
함수의 기본 헝태
- 데이터 타입(자료형) - 함수가 리턴하는 값의 타입
- 함수 이름 - 함수 기능과 밀접한 이름으로 만드는 것이 좋음
- 인수 목록 - 함수에 필요한 값을 전달할 때 사용 (=매개변수 = 전달인자 = 파라미터)
- 함수의 내용 - 중괄호 {} 사이의 영역 안에서 작성
자료형 함수이름(인수목록){
함수의 내용
}
#include <stdio.h>
// 함수
// 더하기 Add 기능 함수
int Add(int a, int b){
return a + b;
}
int main()
{
int i = 10;
int j = 20;
int hap = 0;
hap = Add(i, j);
printf("%d\\n", hap);
return 0;
}
void 타입
void = 타입이 없다라는 의미
결과값을 리턴하지 않는 함수 (= 결과값을 리턴할 게 없는 함수)
#include <stdio.h>
int Add(int a, int b);
void print_Start(){
printf("===== 프로그래밍 시작 =====\\n");
printf("두 개의 정수를 입력하시오 : ");
}
void print_Hap(int result){
printf("두 수의 합은 %d입니다. \\n", result);
printf("===== 프로그래밍 끝 =====\\n");
}
#include <stdio.h>
// 함수 문제 1. 사각형의 넓이를 구하는 함수 작성. 사용자로부터 두 정수(가로의 길이, 세로의 길이)를 각각 입력 받아 함수의 전달인자로 전달하고, 사각형의 넓이를 출력하는 함수를 작성. 그리고 이 함수를 Main에서 호출하여 출력.
void calcRectangle(int width, int height){
printf("사각형 넓이는 %d", width * height);
}
int main()
{
int widthInput , heightInput;
scanf("%d", &widthInput);
scanf("%d", &heightInput);
calcRectangle(widthInput, heightInput);
return 0;
}
#include <stdio.h>
// 함수 문제 2. 사용자로부터 두 수를 입력받아, 두 수를 비교하여 최대값과 최소값을 구하는 함수를 정의. 그리고 main함수에서 이 함수를 호출하여 결과값을 출력
void compare(int a, int b){
if(a > b){
printf("최대값 : %d\\n", a);
printf("최소값 : %d\\n", b);
}else{
printf("최대값 : %d\\n", b);
printf("최소값 : %d\\n", a);
}
}
int main (){
int a , b;
printf("두 정수를 입력하시오 : ");
scanf("%d %d", &a, &b);
compare(a, b);
return 0;
}
#include <stdio.h>
/* 함수 문제 3.
커피 자판기가 있다.
100원 넣으면 '블랙커피',
200원 넣으면 '밀크커피'가 나온다.
자판기가 함수와 같은 블랙박스라고 했었다.
자판기를 함수로 구현.
즉, 사용자로부터 정수형 가격(100, 200)을 받아
100을 입력 받으면 -> 블랙커피
200을 입력 받으면 -> 밀크커피
*/
void coffeeMachine(int money){
if(money == 100){
printf("블랙커피");
}else if(money == 200){
printf("밀크커피");
}
}
int main (){
int money;
scanf("%d", &money);
coffeeMachine(money);
return 0;
}
변수의 범위
- 지역변수변수가 선언된 블록 내에서만 유효하며, 블록이 종료되면 메모리에서 사라진다
함수 호출 순서와 소멸 순서는 반대이다. - 함수의 매개변수도 스택 메모리에 할당되는 지역변수이다.

- 스택 메모리에 존재하는 시간 - 언제 생성되고 언제 소멸되는가?
- 메모리상의 스택(stack) 영역에 저장되며, 초기화하지 않으면 의미 없는 값(쓰레기값)으로 초기화된다
- 블록 내에 선언된 변수
- 전역변수프로그램의 어디에서나 접근할 수 있다메모리상의 데이터(data) 영역에 저장되며, 직접 초기화하지 않아도 0으로 자동 초기화된다
- 프로그램이 시작하자마자 (데이터)메모리 상에 올라가서 프로그램이 종료될 때 메모리 상에서 소멸된다
- 함수 바깥쪽에 선언된 변수
- static 변수지역변수처럼 중괄호 영역에서 선언되지만, 중괄호를 벗어나도 (데이터)메모리상에 고정되어 소멸하지 않는다.함수 내에서 선언된 정적 변수는 전역 변수처럼 단 한 번만 초기화(초기화는 최초 실행 시 단 한번만 수행됨)
#include <stdio.h> void func(){ static int value = 0; value++; printf("%d\\n", value) ;} int main (){ int i = 0; while(i < 5){ func(); i++; } return 0; } // 결과 값은 1 2 3 4 5 로 나온다.
그날 그날 읽은 책들의 페이지 수를 사용자로부터 입력 받으면 최종 누적된 페이지 수에 새로 입력된 페이지 수가 추가로 더해지고, 다시 갱신된 최종 페이지 수가 출력되는 것이다.이 기능을 함수로 구현하되, 페이지의 누적 결과를 저장하는 변수를 전역 변수로도 구현해보고, static 변수로도 구현해라. - #include <stdio.h> void calcPages(int cur){ static int acc = 0; acc += cur; printf("최종 누적 페이지 : %d\\n", acc); ;} int main (){ int cur = 0; while(1){ printf("읽은 책의 페이지 수를 입력하시오 : "); scanf("%d", &cur); if(cur == -1){ printf("더 분발하세요."); break; } calcPages(cur); } return 0; }
- 한번의 출력이 끝나면 다시 읽은 책의 페이지 수를 사용자로부터 입력받고, 누적된 최종 페이지 수를 출력한다. 이 과정을 사용자가 -1을 입력할 때까지 계속 반복한다.
- 책읽기 마라톤은 내가 읽은 책들의 페이지 수를 누적 계산하는 기능이다.
- 문제1. 책읽기 마라톤 기능 프로그램 구현
- 또한, 이렇게 선언된 정적 변수는 지역 변수처럼 해당 함수 내에서만 접근할 수 있다
- 언제 소멸되나? 전역변수와 동일하게 프로그램이 종료될 때 메모리 상에서 소멸한다. 왜냐하면 전역변수처럼 데이터 영역에서 관리되기때문이다.
- 지역변수와 전역변수 반반 섞은 느낌
배열
- 배열 선언 구조
- 배열의 타입 : 배열 요소들의 타입을 나타낸다
- 배열 이름 : 각 배열 요소에 접근하기 위해 배열 이름을 나타낸다
- 배열 길이 : 변수의 개수를 나타낸다
- int array[5] - 배열의 타입 : int, 배열 이름 : array, 길이 : 5
- 배열의 첫 번째 인덱스는 무조건 0부터 시작
- 배열의 초기화 형태 - int array[5] = {1, 2, 3, 4, 5}
- 배열을 사용할 때 일반적으로 배열의 길이를 생략하고 많이 쓴다. 왜냐하면 실무에서는 배열에 들어가는 데이터가 어마무시하게 많기때문에 몇 개라고 정확하게 알기 어렵다. 일일이 데이터의 개수를 세서 배열의 길이를 지정하는 것은 비효율적이다.
- 그래서 배열의 길이를 생략하고 초기값을 넣어준다. 그러면 배열 길이를 지정하지 않아도 컴파일러가 알아서 배열의 길이를 계산해서 지정해준다.
- 배열의 복사
- 같은 타입의 변수끼리 복사가 가능
- 배열도 배열끼리 복사가 가능
- 다음과 같이 변수 복사하듯이 복사하면 에러 발생
int arr1[5] = {1, 2, 3, 4, 5};
int arr2[5];
arr2 = arr1;
error C2106 에러 : 배열은 상수이기때문에 대입 연산자를 통해 값을 넘겨 받을 수 없다.
배열의 이름 자체는 상수이다.
- 배열은 요소끼리 복사해야한다.
#include <stdio.h>
int main (){
int i;
int arr1[5] = {1,2,3,4,5};
int arr2[5];
for(i=0; i < 5; i++){
arr2[i] = arr1[i];
printf("%d\\n", arr2[i]);
}
return 0;
}
#include <stdio.h>
int main (){
/*문제 1. 배열 arr1의 값을 배열 arr2에 복사하되,
배열 요소를 역순으로 저장하도록 하고,
복사된 arr2의 요소값들을 출력하도록 하라.
*/
int i;
int arr1[5] = {1,2,3,4,5};
int arr2[5];
for(i=0; i < 5; i++){
int j = 4;
arr2[i] = arr1[j - i];
printf("%d\\n", arr2[i]);
}
return 0;
}
문자열 변수
- null 문자에 관하여
- 문자열 끝에는 null 문자가 반드시 추가된다.
char str[100] "Beautiful";
- null 문자가 왜 필요한가?
- 문자수는 9개, 배열 개수(길이)는 100개, 91개의 공간이 빈다.
- 91개의 공간에는 쓰레기 값으로 채워져있다.
- 사람은 문자와 쓰레기값을 구분하지만, 컴퓨터는 구분이 불가능하다.
- 컴퓨터가 문자열의 끝을 인식하기 위해 null을 표시한다.
- “Beautiful”의 공간은 9개가 아니라 null을 포함하여 10개이다.
#include <stdio.h>
int main (){
int i;
char str1[100] = "Beautiful";
for(i=0; i<10; i++){
printf("%c", str1[i]);
}
printf("\\n");
printf("str1 = %s\\n", str1);
return 0;
}
포인터
#include <stdio.h>
int main (){
int b = 100;
int *pB = &b; // *는 포인터변수임을 알려주는 기호일뿐이다. 일반 변수와 구분하기 위함.
printf("b = %d\\n", b);
printf("&b = %p\\n", &b); //&b = 0x7ffcbfdef4fc (&p는 16진수로 표현)
printf("pB = %p\\n", pB); //pB = 0x7ffde10afc5c
printf("*pB = %d\\n", *pB); //*pB = 100
return 0;
}
- int *pB에 있는 *pB와 printf에 있는 *pB의 *pB는 서로 다른 pB이다
- int *pB에 있는 *와 printf에 있는 *는 의미가 다르다.
- int *pB에 있는 * : 선언할때 pB가 포인터 변수임을 표시하기 위해 붙임
- 선언 이외에 사용되는 * : 가리키는 해당 메모리의 실제값을 참조하라는 의미
포인터와 배열
배열의 이름은 첫번재 요소의 주소값을 저장하는 포인터다.
포인터 즉, 주소값이라는 것은 다량의 데이터가 있을 때 일일이 그 데이터의 주소값을 가질 필요없고 다량의 데이터가 한 단위로 묶여서 첫번째 주소값만 대표성을 가짐. 그래서 첫번째 주소값만 저장하면 그 데이터 덩어리를 대표하는 것이다.
#include <stdio.h>
int main ()
{
int arr[] = {1, 2, 3, 4, 5}; //배열 선언
for(int i = 0; i < 5; i++){
printf("%d\\n", arr[i]);
printf("%p\\n", &arr[i]);
/*
1
0x7ffd45667420
2
0x7ffd45667424
3
0x7ffd45667428
4
0x7ffd4566742c
5
0x7ffd45667430
*/
}
printf("배열의 이름 : %p\\n", arr); //배열의 이름 : 0x7ffd45667420
return 0;
}
배열의 이름 === 포인터(주소값)
배열의 이름이 포인터이지만 일반 포인터와 결정적인 차이점이 있다??
#include <stdio.h>
int main ()
{
int arr[] = {1, 2, 3, 4, 5};
int temp = 10;
arr = temp; //오류 발생
return 0;
}
temp의 값을 arr이라는 배열의 이름(or 배열)에 대입하려고 시도했지만 오류 발생
→ why? 배열의 이름은 상수이다. 즉, 배열은 포인터 상수이다. 상수를 가르키는 포인터를 의미. 상수라는 것은 값을 변경할 수 없다는 것을 의미한다.
⇒ 배열의 이름은 주소값을 갖는 포인터이지만 상수이므로 주소값을 변경할 수 없다.
함수와 포인터
- 함수의 매개변수를 전달하는 형태는 값에 의한 복사와 참조에 의한 복사가 있다.
- 기본적인 함수의 매개변수 전달 형태는 값에 의한 복사이다.
a와 b는 각각의 메모리를 가지고 있고 값만 복사가 되는 것이다.
배열형의 인자는 포인터형으로 받는다.
- 1-5개 정도까지는 전달인자로 사용할 수 있다. 하지만 그 이상 사용하면 난잡해보임
- 배열을 전달인자로 사용하면 여러 개의 값을 넘길 수 있다.
- 어떻게 배열을 전달하고 받을 것인가? 바로 포인터!
int main()
{
Temp(arr);
}
매개변수 배열 arr는 즉, 배열을 나타내는 arr라는 배열의 이름은 주소값이다.
주소값을 매개변수로 넘기면 매개변수를 받는 입장에서는 주소값을 무엇으로 받아서 메모리에 저장할 수 있는가? → “포인터”로 배열의 주소를 받으면 됨
—> 주소값이 복사가 되고 있는 것이다. ⇒ 참조에 의한 복사
#include <stdio.h>
void func(int *pArr){
for(int i = 0; i < 5; i++){
printf("함수 안의 배열 : %d\\n", *(pArr + i)); //pArr + 1 == pArr[i]
}
}
int main ()
{
int arr[] = {1, 2, 3, 4, 5};
func(arr);
for(int i = 0; i < 5; i++){
printf("%d\\n", arr[i]);
}
return 0;
}
'프로그래머스' 카테고리의 다른 글
| 3월 웹 풀 사이클 데브코스 회고록 (0) | 2024.03.31 |
|---|---|
| 2월 웹 풀 사이클 데브코스 회고록 (0) | 2024.03.03 |
| 1월 웹 풀 사이클 데브코스 회고록 (2) | 2024.02.02 |
| 12월 웹 풀 사이클 데브코스 회고 (1) | 2023.12.29 |
| 11월 웹 풀사이클 데브코스 회고 (0) | 2023.12.29 |