Unit 58 자료형 변환하기
-자료형 변환-
자료형을 지정하여 변환하는 것을 명시적 자료형 변환이라고 한다.
이 명시적 자료형 변환을 하는 방법은 변수나 값 앞에 (자료형)을 붙여주면 된다.
(자료형)<변수>
(자료형)<값>
#include <stdio.h>
int main()
{
float a = 1.23; // float형 변수 선언
int b = (int)a; // a의 형을 int로 바꾼 후 int형 변수 b에 저장
printf("%d", b); // b 출력
}
위 코드는 명시적 자료형 변환을 이용해 float형 변수 a의 값을 b에 저장한 코드다.
int형으로 변환된 값 1이 출력되는 것을 볼 수 있다.
예전에는 명시적 자료형 변환 없이 int b = a; 형식으로 써줘도 작동은 했지만 컴파일 경고가 발생했었다. 하지만 명시적 자료형 변환을 이용해 작성을 하니 컴파일 경고가 발생하지 않는 것을 볼 수 있다.
포인터에서도 역시 가능하다.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *a = malloc(sizeof(int)); // int형 포인터 선언 및 int의 크기만큼 메모리 할당
char *b;
*a = 0x1234; // 0x1234를 저장
b = (char *)a; // char형으로 명시적 형 변환
printf("%x", *b); // b의 값을 역참조해 출력
free(a); // 메모리 해제
return 0;
}
위는 동적할당된 int형 포인터 a를 char형 포인터로 변환해 b에 저장하고 b를 출력하는 코드다.
실행 결과를 보면 a의 값에서 딱 1바이트만큼(0x34, little endian이기 때문에 a의 값이 거꾸로 저장돼 가져올 1byte 값이 0x34가 된다.)만 가져와(변환 과정) b에 저장한 것을 볼 수 있다.
#include <stdio.h>
#include <stdlib.h>
int main()
{
short *a = malloc(sizeof(short)); // short형 포인터 선언 및 short의 크기만큼 메모리 할당
int *b; // int형 포인터 선언
*a = 0x1234; // 0x1234 값 저장
b = (int *)a; // int 포인터 형으로 명시적 형 변환해 b에 저장
printf("%x", *b); // b의 값 출력
free(a); // 메모리 해제
return 0;
}
위는 작은 자료형에서 큰 자료형으로 명시적 형 변환을 한 후 값을 출력하는 코드다.
실행 결과는 0x1234만 출력되는 것이 아니라 앞에 fdfd가 붙어 있는 것을 볼 수 있다. 이 이유는 int형 포인터로 형 변환할 때 4바이트만큼 메모리 주소를 읽기 때문인데, short의 경우 2바이트만 저장하기 때문에 2바이트 외의 다른 메모리 공간을 남은 2byte만큼 침범해 값을 받아와 b에 저장했기 때문이다.
short *a = malloc(sizeof(short));
*a = 0x1234;
int b = *(int *)a; // 형 변환과 동시에 역참조
형 변환과 동시에 값을 받아오고 싶은 경우 위 코드처럼 괄호 앞에 *를 붙여준다면 형 변환과 동시에 역참조해서 변환된 값을 얻을 수 있다.
-void 포인터
void 포인터는 자료형이 정해져 있지 않아 역참조가 불가능(역참조는 메모리 공간에서 해당 자료형의 크기만큼 읽어오는 거지만 void는 크기가 정해져 있지 않기 때문이다.)하지만 void 포인터를 다른 자료형으로 변환하면 역참조가 가능하다.
#include <stdio.h>
int main()
{
int a = 10; // int형 변수 a 선언 및 10 할당
void *b; // void 포인터 b 선언
b = &a; // a의 주소를 b에 저장
printf("%d", *(int *)b); // b를 int형으로 변환함과 동시에 역참조한 값을 출력
}
위 코드는 void 포인터 b에 int형 변수 a의 주소를 저장하고 출력시 b를 int형으로 명시적 형 변환을 함과 동시에 역참조해서 그 값을 출력해주는 코드다.
void를 int형으로 변환해줬고 해당 포인터에는 a의 주소가 저장돼 있었기 때문에 a의 값인 10이 출력된 것을 볼 수 있다.
-구조체 포인터 변환
자료형 변환을 주로 사용하는 상황은 구조체 포인터를 변환할 때라고 한다. 이럴 때는 struct와 구조체 이름 뒤에 *를 붙여주고 괄호로 묶어주면 된다.
(struct <구조체 명> *) <포인터>
((struct <구조체 명> *) <포인터>)-><멤버>
#include <stdio.h>
#include <stdlib.h>
typedef struct a {
int a;
float b;
} A; // 구조체 및 구조체 별칭 정의
int main()
{
A *a1 = malloc(sizeof(A)); // 구조체 포인터 변수 선언 및 메모리 할당
void *ptr; // void 포인터 선언
a1->a = 1;
a1->b = 1.5f;
// 멤버에 값 할당
ptr = a1; // ptr에 a1 주소를 저장
printf("%d\n", ((A *)ptr)->a); // ptr을 구조체 포인터로 변환하여 멤버 a 출력
printf("%f\n", ((A *)ptr)->b); // ptr을 구조체 포인터로 변환하여 멤버 b 출력
free(a1); // 메모리 해제
return 0;
}
위는 구조체와 구조체 포인터 변수, void형 포인터를 선언해, 이 void형 포인터에 구조체 포인터 변수의 주소를 저장한 후 구조체 포인터로 변환하여 멤버들 값에 접근해 출력하는 코드다.
각 멤버들의 값을 제대로 출력하는 것을 볼 수 있다.
Unit 59 포인터 연산 사용하기
-포인터 연산-
포인터에는 메모리 주소가 들어있는데 이 포인터 변수에 덧셈, 뺄셈 연산을 하게되면 메모리 주소가 바뀌게 된다.
이를 이용해서 다른 메모리 주소에 접근하는 등 메모리 주소를 쉽게 옮겨 다닐 수 있다고 한다.
포인터 연산에서는 +, -, ++, --만 사용할 수 있고 *, / 연산자와 실수 값을 사용할 수 없다.
#include <stdio.h>
int main()
{
int a[5] = {0, };
int *b;
int *c;
int *d;
// int형 배열 및 포인터 변수들 선언
b = a; // a의 주소 값을 b에 저장
c = b + 1; // b의 주소 값 +1 한 값을 c에 저장
d = b + 2; // b의 주소 값 +2 한 값을 d에 저장
printf("%p\n", b); // b에 저장된 주소 값 출력
printf("%p\n", c); // c에 저장된 주소 값 출력
printf("%p\n", d); // d에 저장된 주소 값 출력
return 0;
}
위는 int형 포인터 변수 b에 a 배열의 주소를 저장하고 c, d에는 b에 1, 2를 각각 더한 값을 저장하고 b, c, d에 저장된 값을 각각 출력한다.
출력된 주소를 보면 +1, +2 증가된 주소가 아닌 4, 8씩 증가된 주소가 출력되는 것을 볼 수 있다. 이 이유는 포인터 연산을 할 때는 포인터 자료형의 크기만큼 더하거나 빼기 때문이다. 예를들어 +1은 int형의 크기인 4*1해서 4가 더해주는거고 +2는 4*2해서 8이 더해지는 것이다. 즉 sizeof(<자료형>)*<더하거나 뺄 값>으로 생각하면 된다.
#include <stdio.h>
int main()
{
int a[5] = {0, };
int *b;
int *c;
int *d;
// int형 배열 및 포인터 변수들 선언
b = a; // a의 주소 값을 b에 저장
c = b + 1; // b의 주소 값 -1 한 값을 c에 저장
d = b + 2; // b의 주소 값 -2 한 값을 d에 저장
printf("%p\n", b); // b에 저장된 주소 값 출력
printf("%p\n", c); // c에 저장된 주소 값 출력
printf("%p\n", d); // d에 저장된 주소 값 출력
return 0;
}
위 코드는 포인터에 뺄셈을 해본 것이다.
덧셈과 마찬가지로 sizeof(<자료형>)*<뺄 값>을 빼주는 것을 알 수 있다.
#include <stdio.h>
int main()
{
int a[5] = {0, };
int *b;
b = a; // 배열 첫 번째 요소의 메모리 주소를 포인터에 저장
printf("%p\n", b);
b++; // ++
printf("%p\n", b);
b--; // --
printf("%p", b);
return 0;
}
위 코드는 포인터에 ++, -- 연산을 하는 코드다.
마찬가지로 sizeof(<자료형>)*<더하거나 뺄 값>으로 연산이 되는 것을 알 수 있다.
#include <stdio.h>
int main()
{
int a[5] = {0, 1, 2, 3, 4};
int *b;
b = a; // 배열 첫 번째 요소의 메모리 주소를 포인터에 저장
printf("%d\n", *b);
b += 1; // += 1
printf("%d\n", *b);
b++; // ++
printf("%d\n", *b);
b -= 1; // -= 1
printf("%d\n", *b);
b--; // --
printf("%d\n", *b);
return 0;
}
위는 +, -, ++, -- 연산을 한 후 해당 주소를 역참조해 저장된 값을 출력하는 코드다. 배열 같은 경우 각 요소들이 자료형의 크기만큼 떨어져 있으므로 포인터 연산하고 확인할 때 최적의 조건인 것 같다.
맨 처음에는 첫 번째 요소의 주소가 저장되므로 0이 출력되고, +=1을 하면 결국 주소에 4가 더해지기 때문에 두 번째 요소가 출력된다. ++ 역시 4가 더해지기 때문에 세 번째 요소가 출력된 모습이다. -=, --는 주소에서 4를 빼주기 때문에 각각 두 번째 요소, 첫 번째 요소를 출력해준다.
printf("%d\n", *(b--)); // 현재 주소에 저장된 값을 출력한 후 -- 연산을 해줌
printf("%d\n", *(--b)); // -- 연산을 한 주소에 저장된 값 출력
위처럼 --b, b--의 차이가 여기서도 적용된다. 출력시 b--를 해줄 경우에는 현재 주소의 값을 출력한 후 --연산을 하고 --b는 --연산을 했을 때의 주소에 저장된 값을 출력해준다.
-void 포인터의 연산
void 포인터는 자료형의 크기가 정해져 있지 않아서 +, - 연산 역시 불가능하다.
앞과 마찬가지로 void 포인터로 연산을 하고 싶다면 다른 자료형으로 변환 후 해주면 된다. 역참조 역시 마찬가지로 다른 자료형으로 변환 후 연산을 한 뒤 해주면 된다.
예) (자료형 *)<void 포인터> + <값>
#include <stdio.h>
int main()
{
int a[5] = { 0, 1, 2, 3, 4 };
void *b;
b = a+2; // 배열 세 번째 요소의 메모리 주소를 포인터에 저장
printf("%d\n", *((int *)b)); // int형 포인터로 변환한 b를 역참조
printf("%d\n", *((int *)b + 1)); // int형 포인터로 변환한 b에 +1한 값을 역참조
printf("%d\n", *((int *)b - 1)); // int형 포인터로 변환한 b에 -1한 값을 역참조
return 0;
}
+, - 연산한 주소의 값을 역참조해서 출력하는 코드다.
첫 번째는 a+2 주소를 역참조한 값을 출력하므로 세 번째 요소인 2가 출력되고, 두 번째는 int형 포인터로 변환한 b에 1을 더한 값을 역참조하기 때문에 a+3, 즉 네 번째 요소인 3이 출력된다. 세 번째는 int형 포인터로 변환한 b에 -1한 값을 역참조하기 때문에 a-1, 즉 두 번째 요소인 1이 출력된다.
++, --는 동일하기 때문에 생략하겠다.
-구조체 포인터 연산
구조체 포인터 역시 포인터 연산이 가능하다.
(<포인터> <+, - 연산자> <값>)-><멤버>로 하면 된다.
#include <stdio.h>
typedef struct Data {
int num1;
int num2;
} A;
int main()
{
A a[3] = { { 10, 20 }, { 30, 40 }, { 50, 60 } }; // 구조체 배열 선언 및 초기화
A *ptr; // 구조체 포인터 선언
ptr = a; // 구조체 배열 첫 번째 요소의 주소 저장
printf("%d %d\n", (ptr + 1)->num1, (ptr + 1)->num2);
// ptr+1한 주소에서 num1, num2 멤버에 접근
printf("%d %d\n", (ptr + 2)->num1, (ptr + 2)->num2);
// ptr+2한 주소에서 num1, num2 멤버에 접근
return 0;
}
위는 구조체 포인터에서 + 연산을 해본 코드다. 구조체 포인터에서 + 연산을 할 경우 구조체의 크기 * <값>만큼 +가 되기 때문에 구조체 배열에서 다음 요소의 구조체 변수를 통해 멤버에 접근하게 된다.
ptr은 첫 번째 요소의 구조체 변수의 주소를 담고 있었지만 +1, +2를 하고 멤버에 접근하니 두, 세 번째 요소 구조체 변수의 멤버에 접근해 값을 출력하는 것을 볼 수 있다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Data {
int num1;
int num2;
};
int main()
{
void *ptr = malloc(sizeof(struct Data) * 3); // 구조체 3개 크기만큼 동적 메모리 할당
struct Data d[3];
((struct Data *)ptr)->num1 = 10;
((struct Data *)ptr)->num2 = 20;
((struct Data *)ptr + 1)->num1 = 30; // 포인터 연산으로 메모리에 값 저장
((struct Data *)ptr + 1)->num2 = 40; // 포인터 연산으로 메모리에 값 저장
((struct Data *)ptr + 2)->num1 = 50; // 포인터 연산으로 메모리에 값 저장
((struct Data *)ptr + 2)->num2 = 60; // 포인터 연산으로 메모리에 값 저장
memcpy(d, ptr, sizeof(struct Data) * 3); // 동적 메모리가 구조체 배열의 형태와 같은지
// 확인하기 위해 동적 메모리의 내용을 구조체 배열에 복사
printf("%d %d\n", d[1].num1, d[1].num2); // 30 40: 구조체 배열의 멤버 출력
printf("%d %d\n", ((struct Data *)ptr + 2)->num1, ((struct Data *)ptr + 2)->num2);
// 50 60: 포인터 연산으로 메모리의 값 출력
free(ptr); // 동적 메모리 해제
return 0;
}
위는 코딩도장에 나와 있는 예시 코드다.
위처럼 동적 할당을 통해 구조체 3개 크기만큼 메모리를 void형 포인터에 할당해 구조체 배열을 생성할 수 있고 +, - 연산을 통해 각 요소의 멤버에 값을 저장하고 접근할 수 있다.
아래 쪽 memcpy 함수는 동적 메모리로 할당한 void형 포인터가 구조체 배열과 형태가 같은지 확인하기 위해 구조체 배열에 메모리를 복사한 것이다.
실행 결과를 보면 메모리 동적 할당을 통해 제대로 구조체 배열이 만들어졌음을 확인할 수 있다.
Unit 58 ~ Unit 59 문제
num1을 int 자료형으로 변환하는 방법은 명시적 형 변환이라 해서 앞에 (int)를 붙여주면 된다.
답 : d
포인터 ptr을 char 포인터로 변환하는 방법은 앞에 (char *)를 붙여주면 된다.
답 : e
포인터 ptr을 Data 구조체 포인터로 변환하고 멤버에 접근하는 방법은 ((struct Data *)ptr)->로 해주면 된다.
답 : c
base*height/2로 넓이를 구할 수 있는데 이를 float형으로 변환해서 area에 저장해야하므로 (float)를 식 앞에 붙여주면 될 것 같다.
#include <stdio.h>
int main()
{
int base = 21;
int height = 13;
float area;
area = (float)(base * height / 2); // 넓이를 구한 후 float로 명시적 형 변환을 거침
printf("%f\n", area);
return 0;
}
int형 포인터를 short형 포인터로 변환해 0x3344를 출력하게 하는 것이 목적이다. 명시적 자료형 변환을 이용해 앞에 (short *)를 붙여주면 될 것 같다.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *numPtr1 = malloc(sizeof(int));
short *numPtr2;
*numPtr1 = 0x11223344;
numPtr2 = (short *)numPtr1; // numPtr1을 short 포인터로 명시적 형 변환 후 numPtr2에 주소 할당
printf("0x%x\n", *numPtr2);
free(numPtr1);
return 0;
}
void 포인터를 uint64_t 형 포인터로 변환하는 것이 목적이다. 다른 자료형으로 변환할 때와 똑같이 명시적 형 변환을 해주면 될 것 같다. 추가로 값을 바로 출력해줘야하기 때문에 역참조도 붙여줘야한다.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main()
{
uint64_t *numPtr1 = malloc(sizeof(uint64_t));
void *ptr;
*numPtr1 = 12;
ptr = numPtr1;
printf("%llu\n", *(uint64_t *)ptr);
free(numPtr1);
return 0;
}
void 형 포인터 ptr을 Person 구조체 포인터로 변환해 멤버에 접근해서 값을 출력하는 것이 이 문제의 목적이다. 구조체 포인터로 변환하는 것도 자료형 변환과 마찬가지로 명시적 형 변환으로 하되 자료형 대신 구조체 명을 써줘야한다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Person {
char name[20];
int age;
};
int main()
{
struct Person *p1 = malloc(sizeof(struct Person));
void *ptr;
strcpy(p1->name, "고길동");
p1->age = 40;
ptr = p1;
printf("%s %d\n", ((struct Person *)ptr)->name,((struct Person *)ptr)->age);
// 구조체로 형 변환 후 멤버에 접근
free(p1);
return 0;
}
float형 변수 num1에 입력 받은 실수 값을 int형 변수 num2에 저장하는 것이 목적인데, 단 컴파일 경고가 발생하면 안된다고 한다. 컴파일 경고가 발생하면 안되니 명시적 형 변환을 사용해야할 것 같다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
float num1;
int num2;
scanf("%f", &num1);
num2 = (int)num1; // int형으로 명시적 형 변환
printf("%d\n", num2);
return 0;
}
(int)를 써줘서 컴파일 경고 없이 형 변환해 num2에 값을 저장했다.
8byte 크기의 16진수 정수가 입력되는데 이 16진수의 낮은 자릿수 4byte를 출력하는 것이 목적이다. 낮은 자리 4byte를 출력하면 되므로 4byte 크기의 자료형인 int 포인터로 명시적 형 변환을 하면 앞의 4byte는 짤리니 int 포인터로 명시적 형 변환을 하면 될 것 같다.
하지만 문제에서 이미 unsigned int로 출력될 변수가 선언돼 있으므로 int가 아닌 unsigned int로 형 변환을 하면 된다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main()
{
unsigned long long *numPtr1 = malloc(sizeof(unsigned long long));
unsigned int *numPtr2;
scanf("%llx", numPtr1);
numPtr2 = (unsigned int*)numPtr1; // unsigned int 포인터로 형 변환 후 주소 할당
printf("0x%x\n", *numPtr2);
free(numPtr1);
return 0;
}
(unsigned int*)로 unsigned int 포인터로 형 변환을 했다.
void 형 포인터 ptr을 long double 형으로 형 변환 시켜서 입력된 실수를 그대로 출력하는 것이 목적이다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main()
{
long double *numPtr1 = malloc(sizeof(long double));
void *ptr;
scanf("%Lf", numPtr1);
ptr = numPtr1;
printf("%Lf\n", *(long double*)ptr); // long double 포인터 형으로 형 변환 후 역참조
free(numPtr1);
return 0;
}
long double 형으로 형 변환 시킨 후 *로 역참조해 값을 출력하도록 작성했다.
문제가 길지만 간단하게 해야할 것만 정리하면 그냥 ptr을 구조체 포인터로 변환한 후 멤버에 접근하여 mana와 movementSpeed 값을 출력하면 된다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Stats {
float health;
float healthRegen;
unsigned int mana;
float manaRegen;
float range;
float attackDamage;
float armor;
float attackSpeed;
float magicResist;
unsigned int movementSpeed;
};
int main()
{
void *ptr = malloc(sizeof(struct Stats));
struct Stats st;
scanf("%u %u", &st.mana, &st.movementSpeed);
memcpy(ptr, &st, sizeof(struct Stats));
st.mana = 0;
st.movementSpeed = 0;
printf("%d\n%d", ((struct Stats*)ptr)->mana, ((struct Stats*)ptr)->movementSpeed);
// 구조체 Stats의 포인터 형으로 변환 후 멤버에 접근 후 출력
free(ptr);
return 0;
}
포인터 연산은 -, +, ++, --만 가능하고 실수로 연산할 수 없다.
답 : b, c, e, f
unsinged long long은 8바이트기 때문에 연산했을 때 변동되는 메모리 주소는 8바이트다.
답 : d
포인터 연산과 동시에 역참조 연산을 하는 방법은 *(<포인터 연산 식>)으로 해주면 된다.
답 : d, g
void 포인터에서 포인터 연산을 사용해 멤버에 접근하는 방법은 ((struct Data)ptr <+, -> <값>)-><멤버>로 해주면 된다.
답 : e
포인터 연산을 통해 16진수로 0x8, 0x14를 출력시키는 것이 목적이다. numPtrA는 int형 포인터기 때문에 1을 더해줄 때마다 주소에 4씩 더해진다. 이를 이용해서 연산을 수행하면 될 것 같다.
#include <stdio.h>
int main()
{
int *numPtrA = NULL;
printf("%p\n", numPtrA+2); // 8 = 4*2
printf("%p\n", numPtrA+5); // 14 = 4*5(16진수)
return 0;
}
포인터 변수 numPtrA, ptr을 이용해 포인터 연산으로 55, 22를 각 줄에 출력되게 하는 것이 목적이다. 포인터 연산 후 역참조를 통해 해당 주소의 값을 출력하면 될 것 같다.
#include <stdio.h>
int main()
{
int numArr[5] = { 11, 22, 33, 44, 55 };
int *numPtrA;
void *ptr;
numPtrA = &numArr[2];
ptr = numArr;
printf("%d\n", *(numPtrA + 2)); // numArr[4] 요소에 해당하는 주소를 만든 후 출력
printf("%d\n", *((int *)ptr + 1)); // numArr[1] 요소에 해당하는 주소를 만든 후 출력
return 0;
}
구조체 포인터 연산을 통해 구조체 배열의 2번째 요소의 30과 3번째 요소의 60을 출력하는 것이 목적이다. 2번째 요소는 ptr+1을 해준 뒤 x 멤버에 접근하면 될 것 같고, 3번째 요소는 ptr+2를 해준 뒤 y 멤버에 접근하면 될 것 같다.
#include <stdio.h>
struct Point2D {
int x;
int y;
};
int main()
{
struct Point2D p[3] = { { 10, 20 }, { 30, 40 }, { 50, 60 } };
struct Point2D *ptr;
ptr = p;
printf("%d %d\n", (ptr + 1)->x, (ptr + 2)->y); // ptr+1의 x 멤버, ptr+2의 y 멤버에 접근 및 출력
return 0;
}
입력된 주소에서 6, 10바이트 만큼 +된 주소를 출력하는 것이 목적이다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
short *numPtrA;
short *numPtrB;
short *numPtrC;
scanf("%p", &numPtrA);
numPtrB = numPtrA+3; // numPtrA + sizeof(short)*3
numPtrC = numPtrA+5; // numPtrA + sizeof(short)*5
printf("%X\n", numPtrB);
printf("%X\n", numPtrC);
return 0;
}
포인터 연산은 해당 자료형의 크기 * 값 만큼 연산된다. 따라서 numPtrB는 numPtrA에서 +3된 값을 저장하면 되고 numPtrC는 numPtrA에서 +5된 값을 저장하면 된다.
6개의 입력 값이 두 배열에 저장되는데 위 코드를 완성시켜 입력 된 정수 중 세 번째, 다섯 번째를 출력하는 것이 목적이다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int numArr1[3] = { 0, };
long long numArr2[3] = { 0, };
int *numPtr = malloc(sizeof(int) * 3);
void *ptr = malloc(sizeof(long long) * 3);
int num1;
long long num2;
scanf("%d %d %d %lld %lld %lld",
&numArr1[0], &numArr1[1], &numArr1[2],
&numArr2[0], &numArr2[1], &numArr2[2]
);
memcpy(numPtr, numArr1, sizeof(int) * 3);
memcpy(ptr, numArr2, sizeof(long long) * 3);
numArr1[0] = numArr1[1] = numArr1[2] = 0;
numArr2[0] = numArr2[1] = numArr2[2] = 0;
num1 = *(numPtr+2); // numPtr+2(세 번째 입력 값)을 역참조해서 num1에 저장
num2 = *((long long *)ptr+1); // ptr+1(다섯 번째 입력 값)을 역참조해서 num2에 저장
printf("%d %lld\n", num1, num2);
free(ptr);
free(numPtr);
return 0;
}
3번째 입력 값까지 numArr1 -> numPtr에 저장되므로 num1에는 numPtr에서 2 더한 주소를(2*4) 역참조한 값을 넣고, 여섯 번째 입력 값까지 numArr2 -> ptr에 저장되므로 num2 에는 ptr은 void형이므로 long long형으로 형 변환 후 +1한 주소를 역참조해 num2에 저장한다.
구조체 배열의 포인터 연산을 이용해 두 번째 요소의 x, 세 번째 요소의 z 멤버를 출력하는 것이 목적이다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Point3D {
float x;
float y;
float z;
};
int main()
{
void *ptr = malloc(sizeof(struct Point3D) * 3);
struct Point3D p[3];
float result1, result2;
scanf("%f %f %f %f %f %f %f %f %f",
&p[0].x, &p[0].y, &p[0].z,
&p[1].x, &p[1].y, &p[1].z,
&p[2].x, &p[2].y, &p[2].z
);
memcpy(ptr, p, sizeof(struct Point3D) * 3);
memset(p, 0, sizeof(struct Point3D) * 3);
result1 = ((struct Point3D *)ptr + 1)->x; // 두 번째 요소의 포인터 변수 멤버 x의 값을 result1에 저장
result2 = ((struct Point3D *)ptr + 2)->z; // 세 번째 요소의 포인터 변수 멤버 z의 값을 result2에 저장
printf("%.1f %.1f\n", result1, result2);
free(ptr);
return 0;
}
구조체 배열로 ptr이 만들어져 있고 구조체 배열 p의 요소들이 이 ptr로 memcpy 함수를 통해 복사되므로 ptr로 두 번째 요소의 멤버 x, 세 번째 요소의 멤버 z를 구하면 된다.
일단 ptr은 void 형이므로 구조체 형으로 명시적 형 변환을 해준 후 두 번째 요소는 +1, 세 번째 요소는 + 2를 해준 뒤 x, z 요소에 접근하고 그 값을 result1, result2에 저장하면 된다.
'Old (2021.01 ~ 2021.12) > Programming' 카테고리의 다른 글
[PHP] get 방식 처리 in php (0) | 2021.09.21 |
---|---|
[PHP] php의 기본적인 문법 (0) | 2021.09.21 |
c언어 코딩도장 Unit 56 ~ Unit 57 (0) | 2021.04.11 |
c언어 코딩도장 Unit 54 ~ Unit 55 (0) | 2021.03.27 |
c언어 코딩도장 Unit 51 ~ Unit 53 (0) | 2021.03.27 |