Post

C 오답 정리

Review notes for studying c language.

Overview

C언어 공부하며 틀린 것들 정리


Date: 2024년 4월 8일

◼︎ 콜백함수

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>

int calc(int (*q)(int, int))
{
    int result;
    result = (q)(3, 5);
    printf("%d", result);
    return 0;
}
int p(int a, int b)
{
    return (a + b);
}

int main()
{
    calc(p);
    return 0;
}
  1. calc 함수는 매개변수로 함수 포인터 q를 받음
  2. 메인 메소드에서 calc(p)로 → p 함수를 매개변수로서 전달함
  3. calc 함수 내부에서 q라는 함수 포인터는 p라는 함수를 가리키게 되고, p 함수의 주솟값을 받게 됨.
  4. 즉, (q)(3,5)=p(3,5)를 수행하게 되어 return 값은 8인 것.

함수의 매개변수로 다른 함수를 전달해서 호출 함 → 콜백 함수


Date: 2024년 4월 9일

► 나중에 복습할 것

  • 서식 지정자

◼︎ C언어 strchr, 포인터

strchr

  1. 문자열에서 특정 문자를 찾는 내장함수
  2. 만약 문자 c가 문자열 str에 존재한다면, 그 위치를 포인터로 반환
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// strchr
// %s
#include <stdio.h>
#include <string.h>

int length(char a[], char s)
{
    char *p;
    int len = 0;
    p = strchr(a, s);

    printf("%s", p);
    while (*p != 0)
    {
        len++;
        p++;
    }
    return len;
}

void main()
{
    char a[] = "selfcontrol";
    int i = 0;
    i = length(a, 'c');
    printf("%d", i);
}

포인터 궁금한 거

이 부분에서

  1. p에 ‘c’의 메모리 주소를 저장했다.
  2. &a[4]는 a배열의 ‘c’ 위치인데, 출력해보니 다른 주소가 나왔다. → 그 논리대로면 p로 출력해야 했다.
1
2
3
4
5
6
7
8
    printf("%c\n", *p); // 포인터 변수 p가 가리키는 값을 출력
    printf("%d\n", &p); // 포인터 변수 p의 주소번지를 출력
    printf("%d\n", p); // p는 포인터 변수고, p가 가리키는 주소
    printf("%d\n", &a[4]); // a[4]의 주소 출력
99
1829711864
1829711932
1829711932

◼︎ C언어 16진수 변환

16진수 알고 있으면 바로 풀 수 있다. A=10, — F=15

  1. i가 31에서 종료되고, 이를 16진수로 변환
  2. 31을 이진수로 변환 → 11111
  3. 1111을 16진수로 변환 → 0001 11111111을 16진수로 나타내면 F → 1F
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>

int main(int agrc, char *argv[])
{

    int i = 0;
    while (1)
    {
        if (i == 31)
            break;
        i++;
    }
    printf("i=%X", i);
    return 0;
}

◼︎ C언어 서식 지정자

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
int main()
{
    short digit;
    short *ptr;   // 포인터 변수 ptr
    ptr = &digit; // short digit의 주소를 ptr에 저장
    *ptr = 255;   // 포인터가 가리키는 곳의 메모리 주소값이 255

    printf("%d(%04x)", digit, digit);
}
  • %ddigit 변수 값을 정수로 출력
  • %04x는 16진수로 출력하기 위해 사용, 04는 출력을 4자리로 맞추라는 의미. 만약 값이 4자리 미만인 경우 앞에 0을 추가하여 4자리 맞춰줌

추가 출력 형식 지정자 예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>

int main()
{
    char c = 'A';
    float f = 12.34;
    char s[] = "Hello, World";
    int *p = NULL;
    double d = 1.23e-4;
    unsigned int u = 123;

    printf("%c\n", c); // Character
    printf("%f\n", f); // floatn
    printf("%s\n", s); // 문자열
    printf("%p\n", p);
    printf("%e\n", d);
    printf("%u\n", &u); // 123이 출력
    printf("\n");
    printf("%x\n", 0xF1); // 부호 없는 16진 정수
    printf("%X\n", 0xF1); // 부호 없는 16진 정수 대문자
    printf("%o\n", 071);  // 부호 없는 8진 정수
}

Date: 2024년 4월 10일

◼︎ C언어 포인터 함수와 메모리 적재 원리

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>

char n[30]; // 전역 변수
char *so()
{
    gets(n);
    return n;
}

int main()
{

    char *p1 = so();
    char *p2 = so();
    char *p3 = so();

    printf("%s", p1);
    printf("%s", p2);
    printf("%s", p3);
    return 0;
}
1
2
3
4
입력값 
A B C 
출력값은 
CCC.
  1. char n[30]은 전역 변수로 선언되어 있어서, 이 프로그램의 메모리 공간 중 어디에 저장되든지 상관없이 이 프로그램 전체에서 접근 가능하다.
  2. 그리고 so() 함수 안에서 gets(n);이 실행될 때마다, 입력받은 문자열이 n이 가리키는 메모리 공간에 저장된다.
  3. 그리고 return n;으로 n의 메모리 주소를 반환한다.
  4. main() 함수에서 so()를 세 번 호출하면서, 각각 p1, p2, p3n의 메모리 주소가 할당된다.
  5. 하지만, so() 함수를 호출할 때마다 n이 가리키는 메모리 공간의 내용이 변경된다. 따라서, 마지막에 입력된 C가 n이 가리키는 메모리 공간에 저장된다.

Date: 2024년 4월 11일

◼︎ sizeof 함수

sizeof() 함수는 C 언어에서 변수나 자료형의 메모리 크기를 반환하는 내장 함수이다.

1
2
3
4
5
6
int arr[]={1,2,3,4};

sizeof(arr) // arr int 원소를 4 가진 배열이다.
// arr 배열 전체 크기를 바이트 단위로 반환하여, int 원소가 4개이므로 4 * 4 = 16
sizeof(arr[0]) // arr[0] 크기를 바이트 단위로 반환한다.
// arr[0] int형이므로, 4 반환한다.

◼︎ C언어 포인터

2024년 4월 2일 2024년 4월 12일

C언어 포인터를 알고는 있으나, 정확히 숙지되지 않은 것 같아서 다시 정리 해본다.

C언어 포인터와 배열

배열의 요소에 접근하는 여러 방법들이다.

1
2
3
4
5
6
7
8
char  ary[100];

ary[0]       = 'a'; // 배열의 첫 번째 요소에 'a'를 저장
1[ary]       = 'b'; // 배열의 두 번째 요소에 'b'를 저장
*(ary+2)     = 'c'; // 배열의 세 번째 요소에 'c'를 저장
*(&ary[0]+3) = '\\0'; // 배열의 네 번째 요소에 NULL 문자를 저장

printf( "%s\\n", ary); // 배열에 저장된 문자열을 출력

내가 처음에 이해가 안 되었던 것은

ary[0] , arr, *arr+0, 0[ary] 등 C 언어에서 동일한 값을 표현하는 방식이었다.


C언어 배열 특성

포인터를 이해하려면 변수의 주소부터 이해해야 한다.

주소를 쉽게 설명하면, 컴퓨터는 메모리의 집합체이고, 변수는 특정 메모리에 자리를 잡은 위치이며 그 위치를 주소라고 한다.

인덱스0123
abc\0
&a[0]&a[1]&a[2]&a[3]
주소100101102103

ary를 주소로만 따진다면, 다음과 같이 해석할 수 있다.

  • ary[0]은 첫 번째 요소의 주소 100에 0을 더한 100
  • ary[1]은 두 번째 요소의 주소 100에 1을 더한 101

C언어 포인터 특성

1
2
char ary[] = "abc";
char *ptr = ary;

먼저, char ary[] = "abc"; 라는 배열이 있다고 가정했을 때,

인덱스0123
‘a’‘b’‘c’‘\0’
주소1000100110021003

이렇게 메모리에 저장된다.

여기서 ‘a’, ‘b’, ‘c’, ‘\0’는 ary 배열의 각 원소이고, 1000, 1001, 1002, 1003은 각 원소의 메모리 주소이다.

그 다음으로, char *ptr = ary; 라는 포인터 변수가 있을 때 포인터 *ptr은 무엇을 가리키는가?

포인터 변수값 (가리키는 주소)값(메모리 주소)
ptr1000999

이렇게 메모리에 저장된다.

여기서 ptr는 포인터 변수의 이름이고, 1000은 ptr이 가리키는 주소, 즉 ary 배열의 첫 번째 원소 ‘a’의 주소이다.


포인터가 가리키는 값

처음 오히려 어렵게 생각해서 더 이해가 안 갔는데, 단순히 생각했다.

  • 메모리에서 주소는 숫자이므로, 포인터 변수는 단지 숫자가 들어가는 정수 변수일 뿐이다. 포인터 변수 ptr은, ary라는 배열의 주소값 자체를 저장하고 있는 것 뿐이다.
  • 그렇다면, ptr의 주소(자기 주소)는 999고, ptr이 가리키는 값은 1000인 것이다.
  • 그리고 조금 더 생각해보자면, 포인터 변수 ptr 앞에 * 연산자를 놓으면 ptr 변수가 갖고있는 정수 값의 → 값을 구할 수가 있다.
    • ptr 변수 값은 1000이고, 그 주소의 값을 구하면 ‘b’가된다.

풀어서 설명하자면

  • ptr의 값은 ary[0]의 주소이며, *ptr은 ary[0]의 값이다.
  • ptr+2의 값은 ary[2]의 주소이며, *(ptr+2)는 ary[2]의 값이다.

아직도 포인터를 보면 조금은 생각해야 하지만, 메모리에 어떻게 할당 되는지에 대한 이해가 있으면 조금은 쉽다. 그리고 메모리를 조금 더 공부해보면 좋을 듯 하다.


‘**’ ? 더블 포인터

1
2
3
4
5
6
char* st[] ={1,2,3,4};
char** q;
q = st;

printf("%c", **q);
printf("%c", *(*(q+1)));

더블 포인터는 포인터의 포인터로, 포인터 변수가 가리키는 주소 자체가 또 다른 포인터의 주소인 경우 사용된다. 기본적인 포인터가 변수의 주소를 저장하는 것과 달리, 더블 포인터는 다른 포인터의 주소를 저장한다.

예를 들어, char* st[] ={1,2,3,4}; char** q; q = st;라는 코드에서, qst 배열의 첫 번째 요소인 st[0]의 주소를 가리키는 더블 포인터이다.

따라서 **q를 출력하면 st[0]의 값인 1이 출력된다.


► 추가 포인터 예제

포인터와 문자열 예제로 조금 더 이해해보기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>

int main()
{
    char *p = "KOREA"; // 포인터 p 선언, 문자열 KOREA로 초기화
    // p는 전체 문자열  "KOREA"의 시작 주소를 가리키게 됨

    printf("%s\n", p); // p는 KOREA 문자열의 시작 주소를 가리키는 포인터
    printf("%s\n", p + 3);

    printf("%c\n", *p); //%c로 출력한다면 출력 불가
    printf("%c\n", *(p + 3));

    printf("%c\n", *p + 2);
}
// p, *p
// *p는 p가 가리키는 주소에 있는 값
// p가 가리키는 문자열 "KOREA"의 시작 주소이므로, *p는 KOREA의 첫 번째 문자 K를 나타냄

C언어에서 문자열이 어떻게 메모리 저장 되는지?

  • 마지막의 \0 Null 문자.
    • C 언어에서 문자열은 문자의 배열로 표현되며, 문자열의 끝을 나타내기 위해 마지막 문자에 NULL 문자(‘\0’)를 추가한다.
    • 이 NULL 문자는 문자열의 끝을 가리키며, 문자열을 처리하는 함수들이 어디까지가 유효한 문자열인지를 파악할 수 있게한다.
인덱스012345
‘K’‘O’‘R’‘E’‘A’‘\0’
주소100010011002100310041005
  1. printf("%s\\n", p)는 p가 가리키는 문자열, 즉 “KOREA”를 출력한다.
  2. printf("%s\\n", p + 3)는 p가 가리키는 주소에서 3을 더한 위치에 있는 문자열을 출력한다. C 언어에서 문자는 1바이트를 차지하므로 p + 3은 문자열 “KOREA”의 네 번째 문자 ‘E’를 가리킨다. 따라서 “EA”가 출력된다.
  3. printf("%c\\n", *p)는 p가 가리키는 주소에 있는 문자를 출력한다. 여기서 p는 “KOREA”의 시작 주소를 가리키므로 ‘K’가 출력된다.
  4. printf("%c\\n", *(p + 3))는 p가 가리키는 주소에서 3을 더한 위치에 있는 문자를 출력한다. 이는 “KOREA”의 네 번째 문자인 ‘E’를 출력한다.
  5. 마지막으로 printf("%c\\n", *p + 2)는 p가 가리키는 문자에 2를 더한 문자를 출력한다. ‘K’의 ASCII 값은 75이므로 2를 더하면 77이 되며, 이는 ASCII에서 ‘M’을 나타낸다. 따라서 ‘M’이 출력된다.

◼︎ 포인터 연산자

주소 연산자 &

변수 이름 앞에 사용하며, 해당 변수의 주소값을 반환한다.

참조 연산자 *

포인터의 이름이나 주소 앞에 사용하며, 포인터에 가리키는 주소에 저장된 값을 반환한다.

1
2
3
4
5
6
int main(){
	int x=7; //변수 선언
	int *ptr = &x; //포인터 선언
	int *pptr = &ptr; //포인터 참조
	printf("%d", x);
}

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

int main()
{
    int num01 = 1234;
    double num02 = 3.14;

    int* ptr_num01 = &num01;
    double* ptr_num02 = &num02;

    printf("포인터의 크기는 %d이다.\n", sizeof(ptr_num01)); //8
    printf("포인터 ptr_num01이 가리키는 주소값: %#x이다.\n", ptr_num01);
    printf("포인터 ptr_num02가 가리키는 주소값: %#x이다.\n", ptr_num02);
    printf("포인터 ptr_num01 가리키는 주소에 저장된 값: %d.\n", num01);
    printf("포인터 ptr_num02 가 가리키는 주소에 저장된 값: %.2f", num02);
}

◼︎ Call by value와 Call by reference

함수를 호출할 때, 함수에 필요한 데이터를 인수로 전달해줄 수 있다.

값에 의한 전달(call by value)

인수로 전달되는 변수가 갖고있는 값을 함수 내의 매개변수에 복사하는 방식이다. 복사된 값으로 초기화된 매개변수는 인수로 전달된 변수와는 완전히 별개의 변수가 된다. 따라서, 함수 내에서의 매개변수 조작은 인수로 전달되는 변수에 아무런 영향을 미치지 않는다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>

/**
 * @brief Call by value
 * 
 */
void local(int);

int main(void){
    
    int val = 10;
    printf("변수의 초깃값은 %d이다.\n", val);
    
    local(val);

    printf("호출 후 변수 val의 값은 %d이다.\n",val);
    return 0;
}

void local(int num){ //num은 인수로 val 전달받음
//val값 변경하더라도, 원래 인수로 전될된 val값은 절대 변경되지 않음.
    num+=10;
}

참조에 의한 전달(call by reference)

해당 변수의 값을 전달하는 것이 아닌, 해당 변수의 주소값을 전달한다. 즉 함수의 매개변수에 인수로 전달된 변수의 원래 주소값을 저장한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

void local(int*);

int main(void){

    int val = 10;
    printf("변수의 초깃값은 %d이다.\n",val);
    
    local(&val);
    printf("local 함수 호출 후 변수의 값은 %d이다.\n", val);
    return 0;
}
void local(int* num){
    *num +=10;
}

◼︎ % 포맷 지정자

C언어에서는 printf 함수를 사용하여 출력을 제어할 때, 여러 가지 포맷 지정자를 사용할 수 있다. 가장 일반적인 포맷 지정자는 %d, %c, %s, %f 등이다.

  • %d 또는 %i: 정수를 출력
  • %c: 문자를 출력
  • %s: 문자열을 출력
  • %f: 실수를 출력
  • %e 또는 %E: 지수 표현
  • %x 또는 %X: 16진수 표현
  • %o: 8진수 표현
  • %u: 부호 없는 10진수 정수
  • %%: ‘%’ 문자 출력

이러한 포맷 지정자들은 변수의 값이나 표현식의 결과를 다양한 형식으로 출력할 수 있게 도와준다.

예시:

1
2
3
4
5
6
7
8
9
int num = 10;
char ch = 'A';
char str[] = "Hello, World!";
double pi = 3.14159;

printf("%d\\n", num);  // 정수 출력
printf("%c\\n", ch);   // 문자 출력
printf("%s\\n", str);  // 문자열 출력
printf("%.2f\\n", pi); // 소수점 둘째 자리까지의 실수 출 력

◼︎ 비트 연산자 (Bitwise operator)

비트 연산자

비트 (bit) 단위로 논리 연산을 할 때 사용하는 연산자다.

비트 연산자 종류

비트 연산자설명 
&대응되는 비트가 모두 1이면 1을 반환함. (비트 AND 연산) 
  대응되는 비트 중에서 하나라도 1이면 1을 반환함. (비트 OR 연산)
^대응되는 비트가 서로 다르면 1을 반환함. (비트 XOR 연산) 
~비트를 1이면 0으로, 0이면 1로 반전시킴. (비트 NOT 연산) 
«지정한 수만큼 비트들을 전부 왼쪽으로 이동시킴. (left shift 연산) 
»부호를 유지하면서 지정한 수만큼 비트를 전부 오른쪽으로 이동시킴. (right shift 연산) 

Date: 2024년 4월 12일

◼︎ 16진수 비트연산

1
2
3
4
5
6
7
8
#include <stdio.h>
void main()
{
    int a = 0xB4;
    int b = 0xF0;
    printf("%x", a ^ b);
    printf("%x", a & b);
}
  1. 0xB4와 0xF0
  2. 16진수의 표현이다.
  3. 16진수는 0~9, A~F로 구성되며 각각 10진수로 변환하면 0xB4는 180이고, 0xF0은 240이다.
  4. XOR(^) 연산자, AND(&) 연산자
  5. 데이터를 비트 단위로 조회하는 데 사용된다.
  6. *** 비트연산자 종류는 AND(&), OR(), XOR(^), NOT(~), Left Shift(«), Right Shift(») 등이 있다.*
  7. %x
  8. 16진수 형태로 출력하고자 할 때 사용하는 출력 형식 지정자 1. 대문자로 출력하고 싶다면 %X를 사용

Date: 2024년 4월 15일

◼︎ 포인터 기준 배열 접근

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>

int main(int argc, char *argv[])
{
    int a[3][3] = {10, 20, 30, 40, 50, 60, 70, 80, 90};
    int(*p)[3];
    p = a;
    printf("%d", *(p[2] + 1) - *(p[0] + 3));
    return 0;
} 
  • (*p)[3]는 포인터 배열을 선언하는 방법 중 하나이다.
  • 여기서 p는 행을 가리키는 포인터이며, [3]은 각 행에 3개의 열이 있다는 것을 나타낸다.
  • 이를 통해 2차원 배열을 가리키는 포인터를 선언할 수 있다.
  • 이 포인터는 a 배열의 첫 번째 행을 가리키고, p[2] + 1이나 p[0] + 3과 같은 표현으로 배열의 특정 요소에 접근할 수 있다.

Untitled


Date: 2024년 4월 16일

◼︎ sizeOf(구조체)

구조체가 포함하고 있는 요소들 중, 가장 큰 값을 기준으로 그 값의 배수만큼 크기를 가진다.

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
struct SOOJEBI_STRUCT {
	int n; // 정수형 변수 int 4byte
	char c;  // 문자형 변수 char 1byte
 };
int main() {
	// 구조체 변수 s
	struct SOOJEBI_STRUCT s; 

	printf("%ld",sizeof(struct SOOJEBI_STRUCT)); 
	printf("%ld", sizeof(s));
return 0;

틀린 것

  • sizeof(구조체변수)
    • int형 4byte, char형 1바이트 → 총 5byte 라고 생각했다.

애매한 것

  • 데이터 타입 크기

자료형의 배치에 따라 또 달라질 수 있다.

1
2
3
4
5
6
7
8
// 12byte
struct Packet01{
    char	flags;	// 1byte
    int		msg;	// 4byte
    short	count;	// 2byte
}

sizeof(Packet01);		// 12byte
1
2
3
4
5
6
7
8
// 8byte
struct Packet00{
    char	flags;	// 1byte
    short	count;	// 2byte
    int		msg;	// 4byte 
}
//
sizeof(Packet00);		// 8byte

◼︎ 서식 지정자

1
2
3
4
5
6
7
8
9
10
#include <stdio.h> 

int main() {
    char a = 'A';
    int b = 10;
    // 문자 a를 출려갛고, 정수 10을 오른쪽 정렬하여 출력하되
    // 왼쪽에 0을 채워 전체 5자리로 출력
    printf("%c%05d", a, b);
    return 0;
}
  • %c
    • 문자를 출력
  • %05d
    • 정수를 출력하며, 0은 빈공간을 0으로 채우고 5는 총 5자리를 확보하라는 의미다.
    • 왼쪽 빈 칸은 0으로 채워져, ‘00010’ 으로 출력된다.

◼︎ strstr 함수

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]){
    char *p = "hello soojebi world";
    char *pSoojebi = "soojebi";
    char *pTemp;

    pTemp = strstr(p, pSoojebi);

    if (pTemp != NULL){
        printf("%s", pTemp);
    } else {
        printf("%s", p);
    }

    return 0;
}
  • strstr() 함수
    • 두 개의 문자열을 인자로 받아, 첫 번째 문자열에서 두 번째 문자열이 시작되는 첫 번째 위치를 찾아 그 위치를 포인터로 반환한다.
    • 만약 두 번째 문자열이 첫 번째 문자열에 포함되어 있지 않다면, NULL을 반환한다.

◼︎ 반복문

코테를 푸는 탓에 대충 흐름은 눈에 들어온다.. 뭐든 공부하면 얻는 게 있군

아무튼

  1. while loop은 10보다 작은 동안 반복
  2. a를 1씩 증가
  3. a가 홀수인 경우 (%2==1) 반복문의 처음으로 돌아감
  4. a가 짝수인 경우(%2==0) sum에 a값을 누적함 (후위 증감된 a를 저장)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>

int main(int argc, char *argv[]) {
    int a = 7; 
    int s = 0; 
    int sum = 0;

    while (a < 10) { 
        a++;
        if (a % 2 == 1) 
            continue;
        sum += a; 
    }
	 //a가 9일때 while 문 내에서 10으로 증가하고, a는 10인채로 종료
    switch (a / 2) {
        case 2: 
            s++;
        case 3: 
            a += s;
        default:  	 //switch(5)인데 해당 값이 없으므로 default가 실행
            a++; 
    }

    printf("%d%d", s, a); 
    return 0;
}
1
011 //출력값

◼︎ 선택 정렬

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>

int main(int argc, char *argv[]) {
    int a[5] = {3, 4, 10, 2, 5}; 
    int temp;
    int i = 0, j = 0;

    for (i = 0; i <= 3; i++) {
        for (j = i + 1; j <= 4; j++) {
            if (a[i] < a[j]) {
                temp = a[i];
                a[i] = a[j];
                a[j] = temp;
            }
        }
    }

    printf("%d", a[1]);
    return 0;
}
//내림차순 정렬 10,5,4,3,2

◼︎ 길이 반환

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>

int get_length(char *p) {
    int len = 0;
    int i = 0;
    while (p[i] != NULL) {
        len++;
        i++;
    }
    return len;
}

int main(int argc, char *argv[]) {
    char *p = "soojebi";
    int len = get_length(p + 3);
    printf("%d\n", len);
    return 0;
}

◼︎ %c, %s 실수

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>

char *soojebi(char *p) {
    int len = 0;
    int i = 0;
    while (p[i] != ' ') {
        len++;
        i++;
    }
    return &p[i + 1];
}

int main(int argc, char *argv[]) {
    char *p = "soojebi hello world";
    printf("%s\n", soojebi(p + 3));
    return 0;
}
  1. printf("%s\n", soojebi(p + 3));
  2. p[3]부터 soojebi 메소드를 실행한다. ‘ ‘ 전까지 while문을 반복하고, ‘ ‘를 만나면 종료한다.
  3. i가 4일 때 ‘ ‘를 만나 while문이 종료되고, return 값으로 &p[5]를 반환한다.
  4. 그 값은 hello world일 것이고, %s로 NULL값을 만나기 전 까지 출력하라고 했으므로 문장 전체를 출력한다. 1. ★ 실수함. 꼼꼼히 안 보고 %c가 아니라 %s였는데, h라고 답을 적었다.

◼︎ gets 함수

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include<stdio.h> 
#include<stdlib.h> 
 
char n[30];
 
char *test() {
printf("입력하세요 : ");
gets(n);
return n;
}
 
int main()
{
char * test1;
char * test2;
char * test3;
 
test1 = test();
test2 = test();
test3 = test();
 
printf("%s\n",test1);
printf("%s\n",test2);
printf("%s",test3);
return 0;
}
  1. n이라는 전역 문자 배열
  2. test() 함수 호출 → A를 입력받아 n 배열 저장 1. n 배열 주소 반환 → test1 포인터에 저장
  3. test() 함수 호출 → B를 입력받아 n에 저장 → n 배열에 B가 저장되면서, 기존의 A는 사라짐 1. n 배열 주소 반환 → test2 포인터에 저장
  4. test() 함수 호출 → C를 입력받아 n에 저장 → n 배열에 C가 저장되면서, 기존의 B는 사라짐 1. n 배열 주소 반환 → test2 포인터에 저장
  5. test1, test2, test3 모두 n 배열의 주소 가리키고 있음
  6. char 배열에는 C밖에 남지 않음 → 세 포인터를 사용해 출력하면, 모두 ‘C’가 출력됨

Date: 2024년 4월 18일

포인터가 가리키는 값

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>

int main()
{

    char a[] = "ABCDE";
    char *p = NULL;

    p = a;

    printf("%s\n", a);        // ABCDE
    printf("%c\n", *p);       // A
    printf("%c\n", *(p + 4)); // E
    printf("%c\n", (*p) + 2); // C
    printf("%s\n", p);        // ABCDE
    // printf("%s\n", *p);   %s로 출력할 수 없음

    for (int i = 10; i >= 0; i--)
    {
        printf("%c", a[i]);
    }
}
1
printf("%s\n", *p);
  • %s는 문자열을 출력하는 형식 지정자다.
    • 따라서, *p가 가리키는 값이 문자열이어야 하나, *p는 포인터 p가 가리키는 주소에 지정된 값, 즉 “A”를 의미한다. 따라서 %s가 아닌 %c를 사용해야 한다.

This post is licensed under CC BY 4.0 by the author.