Language Study/C

[C/C++] 08 - 02 배열, 문자열과 포인터

지미닝 2022. 11. 21. 02:05

목차

  1. 포인터 변수에 대한 산술 (+,-) 연산
  2. 배열의 이름과 주소
    1. 배열의 이름과 주소
    2. 배열 첨자 연산과 포인터
  3. 문자열과 포인터
  4. 배열 매개 변수와 포인터
  5. 배열 매개 변수 함수 호출에서의 배열 변경
  6. 문자열 입출력 함수 :gets()와 puts()

1. 포인터 변수에 대한 산술 (+,-) 연산 

  • 주소 값은 정수 값과 유사하게 보인다
  • 포인터 변수에 대해 정수와 유사하게 +, -, ++, -- 연산을 할 수 있다.
  • 그러나 정수와의 그 연산결과가 다르다.
  • 포인터 변수가 참조하는 자료형의 크기에 따라 달라진다.

 

2. 배열의 이름과 주소

① 배열의 이름과 주소

  • 배열의 이름은 배열의 시작 주소를 나타내는 포인터/주소 상수이다.
  • 그렇기 때문에 '값'을 변화시키려는 연산은 모두 불가능.
  • 배열 '이름'은 포인터이므로 + 연산이 가능하다.
  • 배열 이름에 n을 더한 것은 첨자에 n을 사용하는 배열 요소의 주소와 같다.
    • num + n = &num[n]

② 배열 첨자 연산과 포인터

✓ 배열의 이름과 주소에서

num + n = &num[n]이 성립함

→  *(num + n) = num[n]

 

※ 배열의 첨자 연산

  • 본질적으로 포인터 연산이다.
  • 첨자 연산과 포인터 연산은 동등하며 상황에 따라 교환하며 사용 가능하다.

※ 배열의 순회!! : c 프로그래밍에서 널리 쓰이는 방식이므로 꼭 익혀두자!

#include <stdio.h>

int main(void){
	int num[10] = {1,2,3,4,5,6,7,8,9,-1};
    int i, *pn;
    
    for (i = 0; i<10; i++)
    	printf("%d\n", num[i]);
    
    for (pn = num; pn < num+10; pn++)
    	printf("%d\n", *pn);
    
    return 0;
}

 

3. 문자열과 포인터

문자열 char 형 배열

  • Null 문자 ('\0')를 덧붙여 끝을 표시함

배열과 포인터

  • pstr이 str을 pointing 하게 값 초기화; &연산자를 사용하지 않았음
    • char *pstr = &str; 동일한 결과이나 거의 표현하지 않는 표현법이다.
    • pstr이 문자열 str을 가르킨다고 일반적으로 표현하지만 엄밀하게 보면 pstr은 str의 제일 첫 항목을 가리키고 있다.
  • str과 pstr은 포인터상수와 포인터 변수다.
    • pstr은 배열과 구별되는 별도의 변수이다. str은 배열 주소를 나타내는 상수이다.
  • Dereferencing, 첨자 연산 적용시 유사하다.
  • pstr은 ++ 연산등을 통해 값을 바꿀 수 있지만 str은 값을 바꿀 수 없다


포인터를 이용한 문자열 순회 Programming

#include <stdio.h>
int main(void){
char *pstr;// pointer
int num  =0, sum=0;// number
char str []="123,456,789";

for( pstr = str; *pstr != '\0' ; pstr++) {
	if (*pstr==  ',') { // newnum
    	sum += num;
        num= 0;
    } else { // a digit
    	num= num *10 + (*pstr-'0');
        }
    }
    sum += num;
    printf("Sum of all values in");
    printf(" CSV[%s] : %d", str,sum);
    
    return 0;
}

4. 배열 매개 변수와 포인터

배열 매개 변수는 본질적으로 포인터 매개변수이다.

배열 형식으로 선언한 매개 변수는 실제로는 주소 값을 가지는 포인터 변수다.

함수 호출 시 배열 이름을 사용하면 배열의 이름이 나타내는 주소 값이 (포인터)매개 변수로 복사된다.

선언에 포함한 배열의 크기는 실제로는 이의미가 없으며 무시된다.

 

5. 배열 매개 변수 함수 호출에서의 배열 변경

C 함수는 Call by Value 특성으로 함수 호출에 쓰인 변수가 함수 호출에 의해 값이 변하지 않는다.

  • 매개 변수의 형식이 배열인 경우, 함수 호출에 쓰인 배열의 주소가 매개 변수로 복사된다.
  • 즉 배열 매개변수는 호출에 쓰인 배열과 별개의 배열이 아니라 그 배열의 시작 주소를 가지는 포인터 변수이다.

 

6. 문자열 입출력 함수: get()와 puts()

✓ gets()함수와 puts()함수

  • 한 번에 한 문자열을 입력/출력 할 수 있다.
  • scanf()를 통해 문자열을 입력 받을 수도 있지만 함수 호출 명령이 더 복잡하고 공백 문자 처리등의 문제로 문자열 입력에 적절하지 않은 경우가 많다.
  • printf()를 통해 문자열을 출력할 수도 있지만 역시 함수 호출 명령이 더 복잡하고 내부 출력 처리 과정도 더욱 복잡해서 효율적이지 않다.

① char *gets(char *str);

  • 표준 입력으로부터 문자열을 읽어 들여 문자형 포인터 str이 가리키는 기억 장소에 저장하고 포인터 str을 리턴한다
  • 매개 변수 str은 함수 입력이 아니라 함수의 출력이다
  • str이 가리키는 기억 장소는 입력 값을 쓸 수 있는 유효한 저장 공간이어야 한다.

② int puts(char *str);

  • str이 가리키는 문자열을 표준 출력에 출력한다. str은 함수 입력이다.
  • 문자열 마지막에 '\n'이 없어도 줄바꿈이 된다.
  • 출력이 성공하면 0이 아닌 값을, 실패하면 EOF값을 리턴한다.

※ 포인터 변수는 초기화 하는 습관을!

  • 변수를 초기화 하지 않으면 Garbage Value를 가진다.
  • Pointer 변수의 초기화는 필수적이다. 적절한 초기화를 하지 않을 경우 부적절한 메모리 공간에 접근하여 값을 읽거나 쓰는 시도로 이루어 질 수 있다. (Run-Time Error)
  • NULL == 0 (주소값 상수)
  • 널 값이면 출력하지 않는다.


Programming - 배열 매개 변수와 포인터

mystrcpy(), mystrcpy2()는 Null-Terminated String인 src를 dest로 복사하는 함수이다.

mystrcpy()는 배열형 매개 변수를 사용하며 첨자를 이용하여 문자열 복사를 수행한다.

#include <stdio.h>
void mystrcpy(char dest[], char src[])
{
    int i=0,j=0;
    while (src[i])
        dest[j++] = src[i++];
    dest[j] = '\0';
}
        
void mystrcpy2(char *dest, char *src ) 
{
    while(*src){
        *dest = *src;
        dest++;
        src++;
    }
    *dest = NULL;
}
int main(void) {
    char mystr1[256];
    char mystr2[256];
    char mystr3[256];
    
    gets(mystr1);
    
    mystrcpy(mystr2, mystr1);
    puts(mystr2);
    
    mystrcpy2(mystr3, mystr1);
    puts(mystr3);
    return 0;
}

배열 매개 변수와 포인터

  • 배열의 이름은 포인터 상수로서 배열 이름 값을 변경하려는 연산은 모두 Syntax error 가 발생한다.
  • mystrcpy()의 매개 변수는 배열형으로 선언되어 있다.
  • 배열형 매개 변수에 대해서는 값을 변화시키는게 가능하다.


보조 - Assignment 연산과 *, ++

2 번째 코드에 mystrcpy3은 에러는 안뜰텐데 이건 값이 원하는 대로 안나올거임.



요약

① 포인터 변수에 대한 +, -, ++, -- 연산, 그리고 우선순위

  • 포인터 변수가 참조하는 자료형의 크기에 비례하여 값이 더해지거나 빠진다
  • 포인터 변수에 대해 단항 연산자인 *,++ 연산이 함께 쓰이면 오른쪽부터 왼쪽으로 연산을 적용한다

② 배열의 이름과 주소

  • 배열의 이름은 배열의 시작 주소를 나타내는 포인터/주소 상수이다
  • 배열의 첨자 연산은 본질적으로 포인터 연산이다

③ 포인터 제 2법칙: p[i] = *(p+n)

④ 배열의 순화(Traversal)

  • 배열의 순회 방법으로는 1) 첨자를 이용하는 방법, 2) 포인터를 이용하는 방법이 있다.
  • 포인터를 이용한 배열을 포함한 복합 자료구조의 순회는 C프로그래밍에서 널리 쓰이는 방식으로 자주 사용하며 익히는 것이 좋다.

⑤ 배엶 ㅐ개 변수는 본질적으로 포인터 매개 변수이다

⑥ 문자열 입출력 함수로 gets()와 puts()가 널리 쓰인다