C

출력 서식 지정자 %

int num = 32;
printf("%o\n", num);  //  8진수: 40
printf("%d\n", num);  // 10진수: 32
printf("%x\n", num);  // 16진수: 20

널 문자 \0

char str[] = "abc";
printf("%d\n", sizeof(str));  // 4 (널 문자 포함한 메모리 전체 크기 출력)
printf("%d\n", strlen(str));  // 3 (순수 문자열의 길이 출력)

char str[8] = "abc";          // 배열의 크기가 미리 지정됨
printf("%d\n", sizeof(str));  // 8 (배열의 전체 크기 출력)
printf("%d\n", strlen(str));  // 3 (순수 문자열의 길이 출력)

++ 연산자

int a[] = {10, 20, 30};
int i = 0;
printf("%d\n", a[i++]);   // 10 (먼저 i 출력, 그 다음 i + 1)
printf("%d\n", a[++i]);   // 30 (먼저 i + 1, 그 다음 출력)

포인터

int a[] = {10, 20, 30};
int *p = a;                 // p는 a[0]의 주소를 가리킴
printf("%d\n", *p++);       // 10 (현재 p인 a[0]의 값 출력 후 p는 다음 칸 a[1]로 이동)
printf("%d\n", *(p+1));     // 30 (현재 p인 a[1]의 다음 칸 a[2]의 값 출력)
printf("%d\n", *p + 1);     // 21 (현재 p인 a[1]의 값 + 1)       

char *ptr = "KOREA";
printf("%s\n", ptr + 2);    // REA (주소를 2칸 뒤로 민 곳부터 끝까지) 
printf("%c\n", *(ptr + 3)); // E   (주소를 3칸 뒤로 민 곳의 글자 하나)

Java

오버로딩 vs 오버라이딩

class Parent {
    void show(Object obj) {         // [오버로딩] 부모의 기본 메서드
        System.out.println("Parent: Object 형을 받음");
    }

    void print() {                  // [오버라이딩] 자식이 덮어쓸 메서드
        System.out.println("Parent: 출력");
    }

    void onlyParent() {             // 부모에게만 있는 메서드
        System.out.println("Parent: 부모 전용 메서드");
    }
}

class Child extends Parent {
    void show(String str) {         // [오버로딩] 부모의 show와 이름은 같지만 매개변수가 다름(별개의 메서드)
        System.out.println("Child: String 형을 받음");
    }

    @Override
    void print() {                  // [오버라이딩] 부모의 print를 덮어쓰기
        System.out.println("Child: 출력");
    }

    void onlyChild() {              // 자식에게만 있는 메서드
        System.out.println("Child: 자식 전용 메서드");
    }
}

public class Main {
    public static void main(String[] args) {
        Parent p = new Child();     // 부모 타입으로 자식 객체 참조 (시야: 부모)
        Child c = new Child();      // 자식 타입으로 자식 객체 참조 (시야: 자식)

        p.print();                  // Child: 출력             (실제 객체 Child가 오버라이딩)
        p.show("test");             // Parent: Object 형을 받음 (부모의 시야에서 문자열을 받는 메서드 찾음)
     // p.onlyChild();              ! 부모의 시야에서는 이 메서드가 안 보이기 때문에 에러

        c.print();                  // Child: 출력
        c.show("test");             // Child: String 형을 받음  (자신의 시야에서 찾음)
        c.onlyChild();              // Child: 자식 전용 메서드    (자신의 시야에서 찾음)
        c.onlyParent();             // Parent: 부모 전용 메서드   (자신에게 없으면 부모로 올라가서 찾음)
    }
}

연산자

class Parent {
    static int shared = 0;          // 가문 공유 재산
    int x = 10;

    Parent() {
        this(5);                    // [4] 나의 다른 생성자로 점프
        System.out.print("P1 ");    // P2 P1
    }

    Parent(int val) {
        shared += val;              // [5] 공유 변수에 +5
        System.out.print("P2 ");    // P2
    }
}

class Child extends Parent {
    int x = 20;

    Child() {
        this(100);                  // [2] 나의 다른 생성자로 점프
        System.out.print("C1 ");    // P2 P1 C2 C1
    }

    Child(int val) {
        // [3] 생략된 부모의 기본 생성자 super()를 자동으로 호출
        shared += val;              // [6] 자식으로 돌아와서 공유 변수에 +100
        System.out.print("C2 ");    // P2 P1 C2
    }
}

public class Main {
    public static void main(String[] args) {
        Child c = new Child();      // [1] Child의 기본 생성자 호출
        System.out.println("공유 변수(shared): " + Child.shared);   // 105
        System.out.println("참조 변수 x: " + c.x);                  // 20 (본인의 x)
    }
}

== vs equals

String s1 = "Java";                 // 문자열 리터럴 (상수 풀에 저장)
String s2 = "Java";                 // 이미 있는 "Java" 주소를 재사용
String s3 = new String("Java");     // 새로운 객체를 힙(Heap)에 생성

System.out.println(s1 == s2);       // true  (주소가 같음)
System.out.println(s1.equals(s2));  // true  (내용이 같음)

System.out.println(s1 == s3);       // false (주소가 다름)
System.out.println(s1.equals(s3));  // true  (내용은 같음) 

Python

split()

x = "abcde"
y = []
for i in x.split():     # 공백이 없으므로 ["abcde"] 반환되고 for문 반복은 1번 발생
    y.append(i[::-1])   # "edcba"
print(y)                # ["edcba"]

List 연산 및 메서드

print([1] + [2])        # [1, 2]
print([10] * 3)         # [10, 10, 10]

x = [1, 2]

a = x.extend([3, 4])    # x = [1, 2, 3, 4]         (낱개로 풀어서 하나씩 이어 붙임)
b = x.append([5, 6])    # x = [1, 2, 3, 4, [5, 6]] (덩어리째로 넣음)
print(a)                # None (반환값 없음!)
print(b)                # None (반환값 없음!)

c = x.pop()             # x = [1, 2, 3, 4] (해당 인덱스 값 꺼내기, 생략 시 마지막)
print(c)                # [5, 6] (반환값 존재)

d = x.remove(2)         # 가장 앞에 있는 해당 값 꺼내기
print(d)                # None (반환값 없음!)

e = x.reverse()         # 거꾸로 뒤집기
print(e)                # None (반환값 없음!)

[:]

x = [1, 2, 3]
y = x               # 두 리스트의 주소는 서로 같음
y[0] = 9
print(y)            # [9, 2, 3]

old_l = [1, 2, 3]
new_l = old_l[:]    # 두 리스트의 주소는 서로 다름
new_l[0] = 9
print(old_l)        # [1, 2, 3] (리스트의 숫자값만 복사됐으므로 원본은 안전)
print(new_l)        # [9, 2, 3]

old_l = [[1], [2], [3]]
new_l = old_l[:]    # 두 리스트의 겉껍데기 주소는 다르나 알맹이 리스트들은 같은 주소 가리킴

공통 주의 사항

소수점

56.0을 "%.2f" 포맷으로 출력 → 56.00 (소수 둘째자리까지 출력)

/ 연산

  • C, Java: 정수 / 정수 = 정수 (5 / 2 = 2)
  • Python: 정수 / 정수 = 실수 (5 / 2 = 2.5)

String + 숫자

  • C: 문자열 + 숫자 연산 금지
  • Java: 숫자를 문자열로 자동 변환해서 이어 붙임
    • "Age: " + 20 = “Age: 20”
  • Python: 문자열 + 숫자 연산 금지 (강제 형변환 필수)
    • "Age: " + 20 = TypeError
    • "Age: " + str(20) = “Age: 20”

char + 숫자

  • C: char 타입은 ASCII 값으로 취급 (저장되는 변수 타입이나 출력 서식 지정자가 중요)
    • int a = 'A' + 2 → 67
    • char a = 'A' + 2 → ‘C’
  • Java: char 타입은 ASCII 값으로 취급
    • 'A' (char) → 'A' + 2 = 67
    • "A" (String) → "A" + 2 = “A2” (따옴표 주의!)
    • 강제 형변환 지정 → (char)('A' + 2) = ‘C’
  • Python: 문자(str) + 숫자(int) 연산 금지
    • ord('A') = 65
    • chr(65) = ‘A’
  • C: printf로 서식 지정자(%d, %s)를 쓴 모양 그대로 출력 (자동 공백이나 줄바꿈 없음)
  • Java: +로 이어 붙이면 공백 없이 붙어서 출력
    • System.out.print("A" + "B") = AB
    • println()은 자동 줄바꿈
  • Python: ,로 구분한 부분을 한 칸 띄우고 마지막에 자동 줄바꿈
    • print("A", "B") = A B
    • print(i, end="") → 출력의 끝부분을 end 옵션으로 변경 가능 (공백이나 줄바꿈 없이 이을 수 있음)

논리값 표기

  • C: true, false 또는 0이 아닌 숫자(보통 1), 0
  • Java: true, false
  • Python: True, False (0 또는 비어 있는 것도 False로 취급됨)

Leave a comment