📖UNIT39
📒문자와 문자열 포인터
include <stdio.h>
int main()
{
char c1 = 'a';
char *s1 = "Hello";
printf("%c\n", c1);
printf("%s\n", s1);
return 0;
}
이 코드를 살펴보자. 먼저 c1에는 'a' 라는 값이 직접 들어가진다.
하지만 s1을 보면 포인터 변수로 선언이 되어있고, "Hello"라는 값의 메모리 주소가 들어가게 되는것이다.
그래서 문자열로 사용이 가능한것이다. 배열도 포인터이다. 이런 문자열의 끝에는 null 문자가 들어가있다.
📒문자열 포인터에 인덱스를 통한 값 변경을 ?
문자열 포인터도 인덱싱을 통해 값 변경을 할 수 있을까?
먼저 이런 포인터에서도 특정 인덱스의 값을 출력은 할 수 있다.
#include <stdio.h>
int main()
{
char *s1 = "Hello";
s1[0] = 'A';
printf("%c\n", s1[0]);
return 0;
}
위와 같은 코드를 작성하고 (값을 바꿔버리는) 컴파일을 하면 오류가 뜨게 된다.
c언어에서 문자열 포인터의 경우 선언을 하자마자 바로 초기화를 해줘야 한다.
📖UNIT40
scanf 함수를 사용할때 일반 변수에 값을 받는다면 &를 해줘야 하지만, 배열의 경우에는 그 자체가 포인터 역할도 되기에 그냥 써주면 된다.
#include <stdio.h>
int main()
{
char *s1 = "Hello";
printf("문자열을 입력하세요: ");
scanf("%s", s1);
printf("%s\n", s1);
return 0;
}
하지만 이전의 경우처럼 위와 같은 코드도 문제를 발생시키게 된다. 포인터로 문자열을 만드는 것 까지는 좋지만,
이후 scanf 함수를 통해 다시 값을 넣어주는 과정에서 오류가 발생하게 된다.
그래서 말록을 이용해 할당해줘야 한다.
📖UNIT41
📒strlen
strlen 함수는 '\0'이 등장할 때 까지 카운팅을 해준다.
그래서 배열의 길이가 1000이 되더라도 'abcde'가 문자열이라면 5를 반환하게 되는 것이다.
이렇게 ...!
📒문자열 비교하기 (strcmp, )
먼저, 문자열이 같은지 다른지 비교하는 함수를 알아보자. strcmp 함수를 사용하면 된다. (string.h)
먼저 strcmp 함수는 문자열이 같다면, 0을 반환한다.
printf("%d", strcmp("aaa", "aaa"));
이런 코드를 작성한다면 0이 출력되는 것이다.
문자열의 대소관계도 비교할 수 있는데, 이건 그냥 그렇구나 하고 알아보자.
📖UNIT42
📒문자열 복사하기 (strcpy)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char *s1 = "hello";
char *s2 = malloc(sizeof(char) * 10);
strcpy(s2, s1);
printf("%s\n", s2);
free(s2);
return 0;
}
코드로 설명하는게 편할 것 같다.
간단하게 보자면 s1의 문자열을 s2로 옮겨야 한다. s2도 포인터로 선언을 해주었기에 malloc을 이용하여 동적할당을 해주어야 한다.
(길이가 10 이하인 문자열만 복사할 수 있다.)
이후 s2에 s1을 복사해준다. 끝
📒문자열 붙이기 (strcat)
#include <stdio.h>
#include <string.h>
int main()
{
char s1[10] = "world";
char s2[20] = "Hello";
strcat(s2, s1);
printf("%s\n", s2);
return 0;
}
문자열 붙이기라고 해서 복사-붙여넣기를 떠올리면 안된다. 이 말은 진짜로 s1의 내용을 s2에다 붙여 넣는다. 이런 느낌이다.
포인터로 선언하더라도 똑같이 진행해주면 된다.
📖UNIT43
📒서식을 지정하여 문자열 만들기 (sprintf)
이번엔 서식을 지정하여 문자열을 만들어보자.
printf("My name is %s", my_name); 이런 코드는 모니터에 출력이 되는 것이지 실제 값으로 저장이 되지는 않는다.
그래서 이러한 값을 변수에 저장하는 방법이 있다.
기본형은 sprintf(배열, 서식, 값)의 꼴을 띈다.
#include <stdio.h>
int main()
{
char s1[20];
sprintf(s1, "Hello, %s", "world!");
return 0;
}
sprintf 함수는 stdio.h 내부에 선언이 되어있기에 따로 헤더파일을 선언해줄 필요는 없다.
%s 뿐만 아니라 %d, %f, %c 등 다양한 서식을 사용할 수 있다.
포인터에 저장을 할 때에도 똑같은 방법으로 진행해주면 된다. 하지만, 꼭 malloc 을 이용하여 동적할당을 배야하는 점 잊지 말자.
📖UNIT44
📒문자열 검색하기 (strchr)
strchr(대상 문자열, 검색할 문자)
위와 같은 형태를 띈다.
#include <stdio.h>
#include <string.h>
int main()
{
char s1[30] = "A Garden Diary";
char *ptr = strchr(s1, 'a');
while (ptr != NULL)
{
printf("%s\n", ptr);
ptr = strchr(ptr + 1, 'a');
}
return 0;
}
strchr() 함수를 여러번 실행하는 이유는, 어떤 문자열에 찾고자 하는 문자열이 여러 개 있을 수 있기 때문이다.
strchr함수는 찾는 문자가 문자열에 있다면, 그 주소값을 반환한다. 그래서 포인터 변수를 선언한 것이다.
while 내에서는 a를 찾을 때 마다 ptr을 그 'a'의 주소에 1씩 증가시켜서 다음 'a'를 찾는 과정을 거치게 된다.
📒문자열 끝부터 검색하기 (strrchr)
strrchr(대상 문자열, 검색할문자) => strchr에 reverse를 의미하는 r이 한 개 더 들어갔다.
strchr 함수와 원리는 같으므로 설명은 생략하겠다.
하지만 중요한 것은 strchr(ptr+1, 'a'); 이 부분이 strrchr 함수에 들어간다면 strrchr(ptr-1, 'a')가 되어야 한다는 것이다.
📖UNIT46
📒문자열과 숫자를 변환하기.
먼저, 문자열과 숫자를 변환해보자. <stdlib.h>
파이썬에선 int("숫자") 이렇게 해주면 바로 변환이 되엇다.
c언어도 굉장히 쉽다. stdlib.h 에 있는 atoi를 해주면 된다.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *s1 = "283";
int num1;
num1 = atoi(s1);
printf("%d\n", num1);
return 0;
}
기본 형태는 atoi(문자열) 이다. Alphabet to Inteager를 의미한다.
📒특정 진법으로 표기된 문자열을 정수로 변환하기. (strtol)
atoi, itoa와 마찬가지로 stdlib.h 안에 선언이 되어있다.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *s1 = "0xaf10";
int num1;
num1 = strtol(s1, NULL, 16);
printf("%x %d\n", num1, num1);
return 0;
}
af10 44816 이 코드를 실행하였을 때 나오는 출력 값이다.
문자열 내에 16진수 임을 의미하는 0x 가 포함되어 있으면 strtol 함수 내에 16을 지정주면 된다.
접두어를 이용하여 8진수 2진수도 처리할 수 있다
저 함수를 좀 더 자세히 알아보자.
char *s1 = "0xaf10 42 0x27C 9952";
만약 문자열이 위와 같은 형태로 주어진다면 어떻게 해야할까 ? 코딩도장의 코드를 가지고 살펴보자
#include <stdio.h>
#include <stdlib.h> // strtol 함수가 선언된 헤더 파일
int main()
{
char *s1 = "0xaf10 42 0x27C 9952"; // "0xaf10 42 0x27C 9952"는 문자열
int num1;
int num2;
int num3;
int num4;
char *end; // 이전 숫자의 끝 부분을 저장하기 위한 포인터
num1 = strtol(s1, &end, 16); // 16진법으로 표기된 문자열을 정수로 변환
num2 = strtol(end, &end, 10); // 10진법으로 표기된 문자열을 정수로 변환
num3 = strtol(end, &end, 16); // 16진법으로 표기된 문자열을 정수로 변환
num4 = strtol(end, NULL, 10); // 10진법으로 표기된 문자열을 정수로 변환
printf("%x\n", num1); // af10
printf("%d\n", num2); // 42
printf("%X\n", num3); // 27C
printf("%d\n", num4); // 9952
return 0;
}
strtol 함수의 기본형을 먼저 알아보자.
strtol(변환할 대상, 끝 포인터, 진법) 으로 표현을 할 수 있다.
아래의 사진을 보면 좀 더 쉽게 이해가 갈 것 이다.
📖UNIT47
회문판열과 N-gram은 이전에 파이썬 코딩도장에서도 만들어 보았다.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void){
char str[30];
int i;
printf("Input String = > ");
scanf("%s", str);
for (i = 0; i < strlen(str) / 2; i++){
if (str[i] != str[strlen(str) - 1 - i])
break;
}
printf("%d \n", i == (strlen(str) / 2));
return 0;
}
그래서 이렇게 간단하게 짜보았다. strlen(str)을 따로 변수로 지정해주는 게 좀 더 속도가 빠를 것 같다.
stdlib.h도 선언을 해주었지만 사용하지 않았다. 그래도 왠지 사용될 것 같아서 선언을 해주었지만...
📖UNIT48
드디어 구조체에 대해서 복습을 한다.
struct Person {
char name[20]; // 이름
int age; // 나이
char address[100]; // 주소
};
이렇게 서로 연관성이 있는 정보들은 struct를 이용하여 묶어줄 수 있다.
구조체는 struct 키워드로 정의한다.
구조체 선언만으로는 구조체를 사용할 수 없다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
struct Person {
char name[20];
int age;
char address[100];
};
int main()
{
struct Person p1;
strcpy(p1.name, "홍길동");
p1.age = 30;
strcpy(p1.address, "서울시 용산구 한남동");
printf("이름: %s\n", p1.name); // 이름: 홍길동
printf("나이: %d\n", p1.age); // 나이: 30
printf("주소: %s\n", p1.address); // 주소: 서울시 용산구 한남동
return 0;
}
이렇게 구조체 변수를 이용하여 변수를 선언해주고, 거기서 사용을 해주어야 한다.
struct Person {
char name[20];
int age;
char address[100];
}p1;
이렇게 해준다면 구조체를 만들고 바로 p1 변수를 선언해주는 것이다.
struct Person p1 = { .name = "홍길동", .age = 30, .address = "서울시 용산구 한남동" };
이렇게 해주면 구조체 변수를 선언함과 동시에 초기화를 진행해줄 수 있다.
📒typedef
하지만, 만들어진 구조체를 사용하려고 매번 struct Person p1;을 해주는것이 귀찮게 느껴질 수도 있다.
그럴 때 typedef를 사용하여 별칭을 정해주면 된다.
typedef struct _Person {
char name[20];
int age;
char address[100];
}Person;
구조체를 이렇게 선언을 해주면
Person p1;
이렇게 사용도 할 수 있다.
즉, struct _Person p1; 과 Person p1은 완벽히 같다.
typedef는 구조체에만 사용되는 것이 아니라 모든 자료형에 똑같이 사용될 수 있으니, 익혀두자.
근데, 이렇게 사용할거면 굳이 _Person 이라는 이름을 지어줄 필요가 없어진다. 그래서 익명구조체라는 것이 있다.
그냥 typedef struct로 만들어주고, 별칭을 Person;으로 만들어준 것이다.
📖UNIT50
#include <stdio.h>
struct x_y {
int x;
int y;
};
int main()
{
struct x_y p1;
struct x_y p2;
double dist = 0;
p1.x = 30;
p1.y = 20;
p2.x = 60;
p2.y = 50;
dist = sqrt((a * a) + (b * b));
printf("%f\n", dist);
return 0;
}
'스터디 그룹 > ProjectH4C' 카테고리의 다른 글
ProjectH4C 3개월 1주차 과제(HackCTF - Basic BOF#1) (0) | 2021.03.18 |
---|---|
ProjectH4C 2개월 4주차 과제 (우리집에 GDB 있는데… 메모리 보고갈래?) (0) | 2021.03.14 |
ProjectH4C 2개월 4주차 과제 (해커스쿨 ftz) (0) | 2021.03.12 |
ProjectH4C 2개월 3주차 과제 (포인터 5문제) (0) | 2021.03.07 |
ProjectH4C 2개월 3주차 과제 (UNIT36, 37, 38) (0) | 2021.03.07 |