배열은 C언어가 제공하는 가장 기본적인 자료구조이면서, 몇 없는 ... 그냥 다(?) 없는 C언어의 자료구조 중 하나이다.
배열이란, 컴퓨터 메모리 상에 같은 타입의 변수를 연속적으로 여러 개를 한꺼번에 정의할 수 있는 방법이다.
배열의 장점은 크게 두 가지가 있다.
1) 공간 효율이 좋다.
구조가 단순하기 때문에 정보 자체를 기억하는 메모리 외에 추가로 소모하는 메모리가 전혀 없이 공간효율이 좋다. 정수형 변수 100개를 저장하는 int arr[100] 배열은 정확하게 정수 100개분만큼의 메모리만을 요구한다.
2) 검색 속도가 일정하다.
배열의 크기가 아무리 커지더라도 검색 속도가 일정한다. 배열의 첨자 연산은 포인터를 통해 시작 번지에 첨자 *요소 크기를 더하는 간단한 동작이므로 임의의 한 요소를 참조하는 시간이 상수이다. int arr[10]에서 arr[9]를 참조하는 시간과 int arr[1000]에서 arr[999]를 참조하는 시간이 똑같다는 얘기이다.
1. 배열 선언
- 타입 이름 변수명[배열길이]; ex) int arr[5];
- 타입 => 배열 요소의 자료형
- 배열길이 => 배열 요소의 개수
- 선언만 하고 초기화 하지 않으면, 각 요소에 쓰레기값들이 저장되어 있게 됨
#include <stdio.h>
int main(){
// 정수형이나 실수형 배열들을 중괄호를 써서 변수의 값을 정함.
// 선언과 동시에 초기화를 진행할 시 초기화 리스트의 타입과 배열의 타입이 반드시 일치해야함.
int a[5] = {10, 20, 30, 40, 50}; // 선언과 동시에 초기화
int b[5] = {10}; // 0번째 값을 10으로 초기화하고 나머지는 모두 0으로 초기화
int c[5] = {15, 25}; // 0번째 값을 15로 초기화하고, 1번째 값을 25로 초기화, 나머지는 모두 0으로 초기화
int d[5] = {}; // 모두 0으로 초기화
int e[5] ; // 초기화 하지 않음 => 각 요소에 trash value 저. 장.
int f[] = {11, 22, 33, 44};
// char 형 배열은 "~~"로 선언 가능. 문자는 0이라는게 NULL 의미
char c[6] = {'H', 'E', 'L', 'L', 'O', NULL}; // c는 문자열 배열이고 값은 H, E, L, L, O
char s[6] = "HELLO"; // s는 문자열 배열이고 값은 H, E, L, L, O입니다.
return 0;
}
// 배열의 크기를 상수식으로 정할 수 있다.
#define N 10
...
int a[N];
2. 배열이 차지하는 메모리의 크기
- sizeof 함수는 메모리 상에서 차지하고 있는 용량 알 수 있다.
- 이 함수를 이용하여 전체 배열 중 하나의 요소로 나누면 쉽게 배열의 크기를 알 수 있다.
#include <stdio.h>
int main(){
int arr[] = {1,2 234, 34, 6634, 754};
printf("%d\n", sizeof(arr)); // 배열이 메모리 상에서 차지하고 있는 용량
// int는 4바이트이고, 6개가 있으므로 출력 결과는: 24
printf("%d\n", sizeof(arr)/sizeof(arr[0])); // 배열의 크기를 구하는 방법 중 하나
// 배열의 전체는 24바이트이지만 요소 하나는 4바이트
// 전체 배열을 요소 하나로 나누면 길이를 구할 수 있다.
// 출력 결과는 24 / 4 이므로 6
printf("%d\n", sizeof(arr)/sizeof(int)); // 이렇게 해도 동일하게 나옴
return 0;
}
3. 문자열 배열
- C언어는 기본적으로 문자열 자료형을 제공하지 않는다. (문자열 쓰겠다고 string을 치고 앉아있던 나.. 드디어 깨달음)
- 문자열 배열 => 문자(Character)를 여러 개 묶어 놓는 형태로 문자열을 표현한다. (C++에서는 string 제공한다고 함.)
- 특이점은 문자열은 컴퓨터 메모리 구조상 마지막에 널(NULL)값을 포함한다. 문자열 마지막에 \0이 있으면 문자열의 끝으로 인식한다. 참고로, NULL은 ASCII 코드로 0이다. 어떠한 값도 의미 있지 않다는 말이다.
- C언어에서는 하나의 문자는 1바이트만 담을 수 있기 때문에,
- 문자의 배열을 표현하기 위해 예를 들면 20자의 배열을 선언한 다음에, 해당 배열에 문자 배열을 할당한다.
- 기본적으로 문자열을 선언할 때는 문자열의 크기보다 배열의 크기가 크도록 해야한다.
// NULL과 띄어쓰기를 포함하여 총 13개의 char 크기가 필요
char str[13] = "Hello world!";
// 배열의 크기 미리 정하지 않고, 배열을 입력하면 알아서 사이즈가 잡히게 됨.
char str2[] = "hello world!";
4. 배열 .. 너 .. 포인터랑 뭐 있어?
=> 배열과 포인터는 표기만 다를 뿐 문법 구조가 유사
=> 배열과 포인터는 표기법을 서로 바꿔 사용 가능
배열 표기법과 포인터 표기법의 관계 | |
배열 | 포인터 |
char data[5]; | char *p; |
[ ] 연산자 사용 | * 연산자 사용 |
배열이 사용하는 메모리 그룹의 시작 주소 기준 |
포인터 변수가 가리키는 메모리의 시작 주소 기준 |
char data[5]; data[1] = 5; *(data+1) = 5; |
char data; char *p = &data; *p = 3; p[0] = 3; |
5. 배열 변수의 이름은 배열의 시작 주소 ✨✨✨
char data[4];
char *p = &data[0]; // 배열의 첫 번째 항목의 주소가 배열 전체의 시작 주소와 같음
char *p = &*(data+0); // 배열 표기법을 포인터 표기법으로 변경
char *p = &*data; // 0 생략
char *p = data; // 주소를 얻는 & 연산자와 주소를 지정하는 * 연산자는 서로 반대 개념의 연산자이기 때문에 서로 상쇄됨.
💡외워.
&a : a의 주소를 가져옴
*a : a를 주소로 하는 곳의 값
=> &(*data) == data
입력받은 문자를 그대로 출력하는 코드이다. 여기에서 scanf("%s", &a);를 쓰면 "warning: format specifies type 'char *' but the argument has type 'char (*)[20]' " 에러가 난다.
Why?!?! 😶🌫️
갑자기 deep(?)하게 들어가자면 &는 해당 변수의 주소를 가리키는 역할을 한다.
[scanf를 사용할 때 내부적으로 구동되는 방식]
1. 값을 입력받는다.
2. 그 값을 레지스터에 임시로 저장하고
3. 변수의 주소를 찾아가 그 주소를 가리키는 메모리에 레지스터에 있는 값(입력한 값)을 저장한다.
4. 레지스터에 있던 값은 지운다.
즉, 값을 입력하려면 변수의 주소가 필요하기 때문에 &를 써야한다.
만약 문자열(%s)을 입력받는 경우에
문자열 자체(포인터거나 배열일 때)는 주소이기 때문에 &를 쓰지 않고 scanf("%s", a);를 쓰면 된다.
#include <stdio.h>
int main(void) {
char a[20];
// 문자열 변수명 a는 그 자체가 주소값을 지칭하므로 &없이 사용. 즉, &a으로 사용하지 않음.
scanf("%s", a);
printf("%s\n", a);
}
6. 포인터로 배열의 주소를 저장하여 사용하기
1) 배열
- 배열은 배열의 시작 주소를 기준으로 색인 작업된 요소의 위치를 계산
- 배열의 같은 요소를 반복적으로 사용하는 경우 효율이 떨어짐
char data[5] = {1, 2, 3, 4, 5};
int sum = 0, select = 2;
// sum 변수에 data[select] (data[2]) 요소 값을 10번 더 함
for(int i=0; i<10; i++) sum = sum + data[select];
// 위와 same
for(int i=0; i<10; i++) sum = sum + *(data + select);
2) 포인터
- 지속적으로 사용되는 배열의 요소는 주소를 포인터 변수에 저장하여 사용
char data[5] = {1, 2, 3, 4, 5};
int sum = 0, select = 2;
char *p = data + select; // char *p = &data[select]; 와 동일한 표현
for(int i=0; i<10; i++) sum = sum + *p;
7. string.h
- strlen = string + length
: 문자열의 길이를 구하는 문자열 표준 함수
- strcpy = string + copy
: 문자열을 복사하는 문자열 표준 함수
- strcat = string + concatenation
: 문자열 뒤에 다른 문자열을 덧붙이는 문자열 표준 함수
배열과 관련된 BOJ
// 2562: 최댓값
#include <stdio.h>
int main(){
int max = 0;
int idx;
for(int i=1; i < 10; i++){ // 몇 번째... 인지 ...
int b;
scanf("%d", &b);
if (max < b){
max = b;
idx = i;
}
}
printf("%d\n%d\n", max, idx);
return 0;
}
// 8958: ox퀴즈
#include <stdio.h>
#include <string.h>
int main(){
int input;
char test[80];
scanf("%d", &input);
for(int i = 0; i < input; i++){
int sum = 0;
int score = 1;
scanf("%s", test);
// strlen() 함수는 문자열의 길이를 반환하는 함수이며, <string.h> 헤더 파일을 필요로 한다.
for(int j=0; j < strlen(test); j++){
if (test[j] == 'O'){
sum += score;
score++;
}
if (test[j] == 'X') score = 1;
}
printf("%d\n", sum);
}
}
포인터 너...... 기다려라...
포인터 배열, 배열 포인터, 상수 포인터.....? pointer......
'SW사관학교 정글 > C언어와 친구들' 카테고리의 다른 글
[C언어와 친구들] 이진 탐색 트리 (BST) (0) | 2022.10.24 |
---|---|
[C언어와 친구들] 구조체(Struct)의 멤버가 포인터일 때, 구조체 포인터 변수 선언(동적메모리할당) (1) | 2022.10.24 |
[C언어와 친구들] 구조체(Struct)와 연결리스트(Linked List) wow (4) | 2022.10.24 |
[C언어와 친구들] C언어의 *포인트는 포인터 (0) | 2022.10.24 |
[C언어와 친구들] C언어를 알아볼까 ? 하잇 ~! (0) | 2022.10.21 |