typedef char *string
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
char *s = get_string("s: ");
char *t = malloc(strlen(s) + 1); // null 종단 문자 추가하기 위해 + 1 해준다.
for (int i = 0, n = strlen(s); i < n + 1; i++)
{
t[i] = s[i];
}
t[0] = toupper(t[0]);
printf("s: %s\n", s);
printf("t: %s\n", t);
free(t); //
}
#include <cs50.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
FILE *file = fopen("phonebook.csv", "a");
char *name = get_string("Name: ");
char *number = get_string("Number: ");
fprintf(file, "%s,%s\n", name, number);
fclose(file);
}
#include <stdio.h>
int main(void){
int arr[6][5] = {{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, 28, 29, 30}};
int n = sizeof(*arr)/sizeof(int);
int m = sizeof(arr)/sizeof(int)/n;
for(int i=0; i< n; i++) {
for(int j =0; j< m; j++){
printf("%d\t", *(*(arr+i)+j));
}
printf("\n");
}
return 0;
}
✅ Heap overflow
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // read함수 사용 위해
int main(){
char* buf = malloc(40);
char* secret = malloc(40);
read(0, secret, 40);
read(0, buf, 100); //취약점
printf("%s\n", buf); //취약점
return 0;
}
✅ Stack overflow
// 너무 큰 지역 변수를 선언하는 경우
int main(void) {
char buf[100000000000000];
return 0;
}
// 미리 정의된 버퍼의 크기를 넘는 경우
int main(void) {
char buf[3];
scanf(“%s”,buf);
// 입력된 값이 3byte를 넘을 경우 다른 영역 메모리까지 침범한다.
// 다른 영역까지도 뛰어넘는 문자열을 넣을 경우 스택 오버플로
return 0;
}
// 재귀 무한 호출
int foo() {
return foo();
}
✅ 공통점
✅ 차이점
✅ strcpy(dest, src)
#include <stdio.h>
#include <string.h>
int main(void){
char destStr[128] = {0,};
char * srcStr = "hello world";
strcpy( destStr, srcStr );
printf("%s\n",destStr);
printf("%s\n",srcStr);
return 0;
}
char buf1[] = "Hello"; //"Hello\0" 이므로 size = 6;
char buf2[] = "BoostCourse"; // size = 12;
strcpy(buf2, buf1);
printf("%s\n", buf2); // "HelloCourse"가 아닌 "Hello\0ourse"가 된다.
✅ strncpy(dest, src strlen(src))
#include <stdio.h>
#include <string.h>
int main(void){
char destStr[128] = {0,};
char * srcStr = "hello world";
strncpy( destStr, srcStr, sizeof(destStr)-1 ); // 널 종단문자 때문에 -1을 해준다.
printf("%s\n",destStr);
printf("%s\n",srcStr);
return 0;
}
char buf1[] = "Hello"; //"Hello\0" 이므로 size = 6;
char buf2_1[] = "BoostCourse"; // size = 12;
char buf2_2[] = "BoostCourse"; // size = 12;
strncpy(buf2_1, buf1, sizeof(buf1));
strncpy(buf2_2, buf1, sizeof(buf1) - 1);
printf("%s\n", buf2_1); // "Hello\0ourse"가 된다.
printf("%s\n", buf2_1); // "HelloCourse"가 된다.
strncpy(dest, origin, n)
n <= sizeof(origin)
n <= sizeof(dest)
✅ strcpy vs strncpy
strncpy는 복사할 대상의 크기를 정해주므로 한 번더 점검 할 수 있기 때문에 오버플로우 예방에 있어 strncpy가 strcpy보다 더 안전하다고 생각한다. 그러나 stncpy도 2번째 문자열의 길이가 1번째 문자열 공간보다 많다던가 첫번째 문자열보다 더 큰 사이즈를 입력한다면 에러가 날 수 있기 때문에 완전히 안전하다고 할 수는 없다.
✅ memset
#include <stdio.h>
#include <string.h>
#include <memory.h>
int main(void){
char ptr[2];
memset(ptr, '*', sizeof(char) * 2);
puts(ptr);
return 0;
}
✅ memcpy
#include <stdio.h>
#include <string.h>
int main(void){
char str1[50] = "Hello BoostCourse";
char str2[50];
char str3[50];
memcpy(str2, str1, strlen(str1) + 1); // 널 종단문자 추가
memcpy(str3, "Hello",5);
// puts(const char * str) : ‘\0’까지의 문자열을 출력하는 함수
puts(str1); // Hello BoostCourse
puts(str2); // Hello BoostCourse
puts(str3); // Hello
return 0;
}
✅ memmove
#include <stdio.h>
#include <string.h>
int main(void){
char str[50] = "Hello BoostCourse";
puts(str); // Hello BoostCourse
printf("--> memmove\n");
memmove(str + 17, str, 5);
puts(str); // Hello BoostCourseHello
return 0;
}
✅ memcmp
#include <stdio.h>
#include <string.h>
int main(void){
char str1[50] = "Hello BoostCourse";
char str2[50] = "Hello BoostCourse";
char str3[50] = "Hello";
if (memcmp(str1, str2, strlen(str1)) == 0){
printf("str1과 str2는 일치합니다.\n");
}else {
printf("str1과 str2는 일치하지 않습니다.\n");
}
if(memcmp(str1,str3, strlen(str1)) == 0){
printf("str1과 str3는 일치합니다.\n");
}else {
printf("str1과 str3는 일치하지 않습니다.\n");
}
return 0;
}
참고 사이트
#include <stdio.h>
void sort(int n, int arr[]);
int main(void){
int n = 7;
int arr[7] = { 0, 25, 10, 17, 6, 12, 9 };
sort(n, arr);
return 0;
}
void sort(int n, int arr[]){
int temp;
int cnt;
for(int i = 0; i < n; i++){
cnt = 0;
for(int j = 0; j < n - 1; j++){
if (*(arr + j) > *(arr + j + 1)){
temp = *(arr + j);
*(arr + j) = *(arr + j + 1);
*(arr + j + 1) = temp;
cnt++;
}
}
if(cnt == 0)
break;
}
for(int i = 0; i < n; i++){
printf("%d\t",*(arr+i));
}
printf("\n");
}
학교다닐때 가장 이해가 안갔던 포인터를 드디어 배웠다. 여러 언어를 배우고 다시 배워서 그런지 확실히 예전보단 이해가 더 잘되었다. 이 강의를 1학년때 접했더라면 더 이해하기 수월했을텐데.. ! 모든 컴공학생들이 1학년때 필수로 보았으면 한다.
1번 문제를 통해 2차원배열을 이중포인터로 활용하는 방법에 대해 알게되었다. *(*(arr+i)+j)
이 부분이 핵심인데 일단 1차원 배열과 달리 arr은 2차원 배열이기 때문에 *(arr+i)
는 값이아닌 주소값이 나온다. 그러므로 *(arr+i)+j
는 주솟값을 가지며 값을 얻으려면 *(*(arr+i)+j)
로 표현해주면 된다.
2번 문제를 풀며 스택 오버플로우와 힙 오버플로우에 대해 공부하면서 각각이 무슨역할을 하는지 정확히 알 수 있었다. 마지막 3번 문제는 1번 문제를 풀었다면 수월하게 풀 수 있었던 문제라 생각한다.
갈수록 점점 더 재밌어지는 코칭스터디..! 벌써 다음주가 마지막이란게 놀랍다. 언제 또 한 달이 지났는지.. 요즘들어 시간이 참 빠르게 가는것 같다 😭 그럼 다음주차도 화이팅 !!!