<3일차>


사쿠라료칸 -> 에노시마 전철(에노시마 섬, 슬램덩크 성지순례,) -> 미요시(미슐랭 1스타) -> 하치만구 -> 

요코하마 브리즈베이호텔 -> 요코하마 관광(차이나타운, 야마시타공원, 랜드마크타워) -> 브리즈베이 호텔




가마쿠라역 -> 요코하마역은 JR 30분이 채 걸리지 않는다. 이 전 포스트에서도 강조했지만 가마쿠라역 주변에 딱히 대단히 볼건 없어도, 미요시 우동이 넘사벽으로 맛있으므로 요코하마에 들린다면 왕복 1시간 투자해서 가볼만하다. 물론 시간 여유가 된다면 간 김에 에노시마 라인 관광을 하면 더더욱 좋고. 





마지막날 숙소는 괜찮은 호텔에서 스파하면서 편히 쉬자는 생각에 요코하마 브리즈베이 호텔&스파로 예약했다. 평일이라서 조식포함 6만원으로 가격도 나쁘지 않았다(스탠다드 더블룸 기준). 문제는 체크인하면서 스파 이용을 물어봤더니, 그 '스파'가 온천을 말하는게 아니고 마사지 받는 곳을 말하는 것이라고 한다... 아니 이름부터 스파가 들어가길래 당연히 온천욕 가능한 줄 알았는데 여기서 1차 멘붕하고, 다음날 조식도 상당히 별로라서 그닥 인상이 좋지 않았다. 그나마 숙소는 깨끗하고 깔끔해서 쉬는건 편히 쉴 수 있었다.(근데 공간도 사쿠라 료칸이 더 넓다!) 


이름에 낚인 빡침을 누르고 전반적으로 호텔을 평하자면, 가격 대비해서 숙소 시설은 좋은 편이긴하다.(하지만 비수기 평일 가격이라 주말은 가격이 크게 다를 수 있다.) 그리고 조식은 그냥 별로고 프론트는 한국인 직원이 있어서 좋긴 했다. 


너무 피곤한 상태라서 1시간정도만 호텔에서 쉬고 다시 출발하였다. 




요코하마 시내의 관광지는 차이나타운, 야마시타 공원, 랜드마크 타워 등이 있는데 모두 걸어서 볼만한 거리이다. 브리즈베이 호텔에서 걸어가기엔 조금 애매해서 가장 먼 차이나타운까지는 전철로 가고, 돌아오면서 하나씩 둘러보고 걸어서 호텔로 복귀하도록 계획하였다. 차이나타운은 먹을거리는 꽤 있었지만 점심을 너무 과하게 먹어서 뭘 먹지는 않았다. 그 외에는 솔직히 볼거리는 없고 요코하마 돔 구장이 바로 옆에 있길래 무빙샷으로 쓱 둘러만 보았다. 



차이나타운에서 야마시타 공원은 걸어서 5분~10분으로 아주 가깝다. 2일차처럼 벤치에서 일몰을 기다렸다. 이 날은 시간을 잘 맞춰서 30분정도만에 야경을 볼 수 있었다. 기다리는 동안 편의점에서 음료수와 푸딩을 사왔는데, 별 생각안하고 나왔더니 스푼이 따로 없었다... 편의점에서 주는지는 잘 모르겠지만 일단 점원한테 물어는 보도록 하자. 




요코하마는 야경이 유명한 도시이다. 사진에는 그다지 잘 나타나지 않았지만, 야마시타 공원에서 왼쪽을 바라보는 야경(위 사진)이 굉장히 아름답다. 반대편에도 무슨 배인지는 모르겠지만 조명이 달려있는 배가 있어서 예뻤다. 평일이라 그런지 사람이 적고 날씨도 좋아서 야경 구경하기에 최고로 좋은 날이었다.



야마시타 공원 바로 옆에는 마린타워가 있다. 여기도 야경을 볼 수 있는 전망대가 있지만, 나는 이보다 좀 더 비싸지만 더 높은 랜드마크 타워에 가기로 했으므로 올라가지는 않았다.



야마시타 공원 -> 아카렌가 창구로 오는 길에 오산바시 국제 여객 터미널이 있다. 바다쪽으로 볼록 튀어나온 모양 덕분에 여기서 보는 야경도 굉장히 훌륭하다. 지도에서 보는것보단 꽤 길었는데, 목조 바닥과 구조가 독특하였다. 야마시타공원 못지않게 야경보기 좋은 곳이고 위치도 가까우므로 꼭 방문하도록 하자. 자세한 모습은 여기의 포스트에 잘 나와있다.



아카렌가 창고도 바로 옆에 붙어 있다. 아카렌가 창고는 이전에 창고로 활용되던걸 개조해서 식당과 기념품점 등으로 바꿔놓은 곳이다. 붉은 색 벽돌이 인상적인데, 하코다테에도 있는 아카렌가 창고와 동일한 컨셉이다. 이미 밤시간이라서 기념품점은 문을 닫았고, 식당들만 열어놓아서 별로 구경할 건 없었다. 



쭉 걸어서 요코하마 랜드마크 타워까지 가는 길에 놀이공원인 요코하마 코스모월드를 마주쳤다. 야경의 한 포인트를 담당하는 녹색 불빛의 대관람차가 인상적이다. 월요일 저녁이긴 하지만 사람이 없어도 너무 없었는데, 놀이공원 유지는 어떻게 하는지 모르겠다... 



중앙 좌측에 보이는 저 빌딩이 요코하마 랜드마크 타워이다. 야마시타 공원에서 오산바시 터미널, 아카렌가 창고, 코스모월드를 지나 여기까지 오는데 대략 3km정도는 넘게 걸은 것 같다. 이미 체력이 바닥난 상태여서 빠르게 전망대로 올라갔다.






요코하마 전망대의 가격은 1000엔이다. 그리 만만치 않은 금액이지만, 돈 값은 확실히 하는 야경을 감상할 수 있다. 저 멀리 도쿄시내와 도쿄만의 모습이 보이고, 낮에는 후지산도 볼 수 있다. 무엇보다도 요코하마 시내의 야경이 끝내준다. 도쿄의 전망대와는 다른 맛의 야경을 제대로 감상할 수 있다. 여담이지만, 여기 엘레베이터가 무지 빠르다. (안내할 때 뭐 세계에서 몇 번째로 빠르다 어쩌구 한 것 같은데 잘 기억은 안난다.)




랜드마크 타워 전망대에서 야경을 본 뒤에 브리즈베이 숙소로 돌아왔다. 숙소에서 좀만 쉬고 편의점에서 맥주나 좀 사올 생각이였는데, 진짜 뒤질거 같아서 그냥 씻고 잤다(점심에 배터지게 먹은게 꺼지지도 않아서, 야마시타 공원에서 산 푸딩만 먹고 저녁도 스킵했다.). 결국 이번 일본 여행에서 1,2일차는 타이레놀 때문에, 3일차는 과도한 피로 때문에 알코올 섭취를 전혀 안하는 건전 여행이 되고 말았다. 3일차는 가장 빡세게 걸은 날인데, 이게 말이 23km에 34000 걸음이지, 실제로는 저 중에 절반을 캐리어 끌고 땡볕에서 걸은거라서 더더욱 힘들었다.

Stack Overflow에는 프로그래밍 전반에 걸쳐서 다양한 질문들이 있고, 수준 높은 답변들도 상당히 많다. 훌륭한 답변이 달린 질문을 읽고, 해당 주제를 보다 심층적으로 공부해보는 것이 큰 도움이 될 것이라고 생각하여 이 시리즈를 시작하였다. 주제는 되도록 프로그래밍 전반에 걸친 범용적인 주제들로 선정하고자 한다. 


* 부족한 부분도 있고, 틀린 부분도 있을 수 있으니 발견하시면 댓글로 알려주시면 감사하겠습니다. 주제 추천도 받습니다.



What is the difference between char s[] and char *s?



<1>

C의 꽃이자 가장 헷갈리는 부분이 포인터이다. 그런데 배열 이름(정확하게는 배열 타입)은 포인터와의 유사성으로 인해 이 난해함을 더욱 증폭시킨다. 처음 c를 공부할 때 "배열 이름은 몇 가지 예외를 제외하고는 기본적으로 포인터와 같다. 일반적으로 배열 이름을 상수 포인터라고 지칭한다."라고 배운 바가 있다. 하지만 안타깝게도 예외가 '몇 가지' 정도가 아니라서 배열 이름을 상수 포인터라고 지칭하는 것은 많은 문제점을 야기할 수 있다. 이번 주제에서는 배열 이름과 포인터의 차이점을 중점적으로 살펴보고자 한다.



<2>

왜 '상수 포인터'라는 말이 붙었는지부터 살펴보자. 먼저 일반적인 포인터의 경우 


1
2
char * p = "hello";
= "world";
cs


와 같은 구문이 전혀 문제가 없이 동작한다. 즉 포인터가 가르키는 대상을 원하는대로 변경할 수 있다(물론 이 때 가비지가 발생하지 않도록 프로그래머가 신경을 써줘야 한다.). 하지만 배열은 다르다.


1
2
char a[] = "hello";
= "world";    // illegal!
cs


위와 같이 a가 가르키는 대상을 변경할 수 없다. 이런 특성 때문에 배열 이름을 상수 포인터라고 지칭하는 경우가 상당히 많다. 하지만 엄밀하게 따지면, 배열은 포인터가 아니다. 아래에서 자세히 살펴보자.



<3>

여기에 질문 답변식으로 비교적 상세하게 배열 이름과 포인터에 대해 다룬다. 또한 나무위키의 항목도 훌륭하게 정리되어 있다. 이들을 기반으로 배열 이름과 포인터 사이의 변환에 대해 정리하자면 다음과 같다.


배열 이름은 수식에서 다음의 예외를 제외하고는 해당 배열의 첫 번째 원소를 가르키는 포인터로 변환된다. 단, 이 때 변환되는 포인터는 lvalue가 아니다.

(lvalue와 rvalue에 대해서는 링크를 참조)


예외 1) sizeof의 피연산자일 때

예외 2) &의 피연산자일 때

예외 3) char arr[] = "hello"; 와 같이 초기화할 때


이 규칙을 기반으로 <2>를 생각해보면, 배열 이름은 'lvalue가 아닌 포인터'로 변환되므로 수식의 좌측에 놓일 수 없다. 따라서 배열 이름이 새로운 문자열을 가르키도록 변경할 수가 없다. 


자 이제 '배열은 배열이고 포인터는 포인터다. 수식에서 배열 이름은 위의 규칙을 기반으로 포인터로 변환된다'라는 걸 머리속에 집어 넣고 스택오버플로우의 질문을 들여다 보자.



<4>

이제 위에 링크한 스택오버플로우의 첫 번째 답변을 보면 다음과 같은 차이점이 보인다.


1) char a[] = "hello";

2) char * p = "hello";


\begin{center}\vbox{\input{cfaqs-ko-1.epic}
}\end{center}

 (그림 출처 : 링크)


1)는 읽기 전용 메모리에 "hello"를 쓰고, 이를 복사하여 배열 a에 새로 메모리를 할당한다. 따라서, s[1] = 'X'; 와 같은 쓰기가 가능하다. 반면에 2)에서는 읽기 전용 메모리에 "hello"를 쓰고, 이를 가르키는 포인터를 생성한다. 따라서 p[1] = 'X' 와 같은 변경이 불가능하다.


왜 이러한 차이가 발생할까? '배열은 배열이고, 포인터는 포인터' 이기 때문이다! 배열은 같은 타입의 원소들이 연속적으로 미리 할당되어 있는 메모리 공간이며, 포인터는 어떠한 종류이든지 그저 가르킬 뿐이다. 2)에서 포인터는 읽기 전용 메모리 영역을 가르키므로 수정이 불가능하게 되는 것이다. 반면에 1)과 같이 선언했더라도, 배열은 연속적이며 미리 할당된 메모리 공간을 보장한다. 따라서 읽기 전용 메모리 영역을 그저 가르키는 것이 아니라, 메모리 영역을 새로 할당 받게 되는 것이다. 당연히, 할당 받은 메모리 공간에서 수정이 가능하다.



<5>

그렇다면 함수에 사용 될때는 어떨까? 우선 반환될 때를 살펴보자. 

1
2
3
4
5
6
7
8
9
10
11
12
// This successfully returns "Hello, World"
char* function1()
{
    char* string = "Hello, World!";
    return string;
}
// This returns nothing
char* function2()
{
    char string[] = "Hello, World!";
    return string
}
cs

(출처 : 링크)



<4>를 바탕으로 추측을 해볼 수 있다. 먼저 function1()의 "Hello, World!"는 함수의 스택 프레임이 아니라 읽기 전용 메모리에 위치할 것이고, string은 이를 가르키게 될 것이다. 따라서 함수가 종료되어도 "Hello, World!"는 무사히 살아남게 되고 string도 정상적으로 "Hello, World!"를 가르킬 수 있다.


function2()에서는 어떨까? <4>에서 본 대로, "Hello, World!"는 복사되어 string 배열에 새롭게 할당될 것이고, 이는 지역 변수이므로 당연히 function2()의 스택 프레임에 위치하게 된다. 그리고 fucntion2()의 스택 프레임은 반환과 동시에 해제될 것이므로 반환 후에 string이 가르키는 곳에서는 아무것도 존재하지 않는 허상 포인터(dangling pointer)가 될 것이라고 예상할 수 있다.



<6>

흥미로운 점은 배열 이름이 함수의 매개변수로 사용되었을 때이다. 여기서는 특이하게도 배열 이름이 완전하게 포인터로 변환된다. 이 내용은 메인 질문의 두 번째 답변에 나와있다. 


1
2
void foo(char *x);
void foo(char x[]); // exactly the same in all respects

cs


매개변수로 사용했을 때의 한해서, 배열 이름은 포인터와 완전하게 동일하다. 배열 전체를 함수 매개변수로 넘겨주게 될 경우엔, 함수의 스택 프레임이 너무 비대해지는 문제점 때문에 포인터로 변환하는 것이 아닐까?(내 생각)



<7>

여기에 내가 정리하지 못한 예외가 더 있는지는 모르겠다. C는 함정이 빈번한 언어인데, 이를 제대로 공부하기란 여간 어려운 것이 아니다.(제대로 공부해본적은 없지만 아마도) 그래도 그 함정카드 중 하나인 배열 이름과 포인터의 관계를 이 포스트를 통해서 조금이나마 정리를 해보고자 하였다.


분노의 포도

존 스타인벡

494쪽(1권) + 497쪽(2권)

17.12.17 ~ 18.01.04(19일)


농가인 조드 일가가, 모래 폭풍과 트랙터 때문에 농지를 잃고 오클라호마에서 쫓겨나게 된다. 조드 일가는 캘리포니아에서 인부를 구하고 있으며, 일자리가 넘쳐나는 곳이라는 전단지를 보고, 가진 재산을 모두 처분하고 트럭을 타고 캘리포니아까지 힘겹게 나아간다. 66번 국도에는 조드 일가와 마찬가지로 일자리를 찾으로 캘리포니아로 향하는 수많은 차량 행렬이 끊임없이 이어진다. 마침내 캘리포니아에 도착하지만, 그곳에는 이미 일하러 온 수 많은 사람들과 지주들의 담합, 캘리포니아인들의 박해로 인해 일자리도 찾기 어렵고, 일당은 계속해서 낮아지는 상황이었다. 조드 일가는 그런 와중에서 고생을 해가며 이리저리 옮겨다니며 어떻게든 살아남기 위해 안간힘을 쓴다.


총 1000쪽 짜리 소설이지만 스토리는 굉장히 단순하다. 위에서처럼 조드일가가 고향을 떠나 캘리포니아로 향하고, 거기서 생고생을 하는 내용이 거의 전부다. 하지만 그런 단순한 구성을 세밀하게 묘사하며, 몰입하게 만드는 작가의 솜씨가 뛰어나다. (물론 엄청 재미있다고 할 정도의 몰입감은 아니다.) 대공황 시절의 이주민들이 겪었던 고난이 아주 생생하게 묘사되어 있으며 이로 인해 캘리포니아에서는 금서로 지정된 적도 있다고 한다. 또 한가지 특징으로, 총 30장으로 구성되어 있는데, 그 중 절반의 장을 조드 일가의 이야기로(=메인스토리) 나머지 절반의 장을 미국 전반의 사회를 묘사하는 장으로 활용하고 있다는 점이다. 미국 사회를 묘사하는 장은 분량은 훨씬 적지만 소설 중간 중간의 분위기를 환기시키며 바로 다음 장의 내용을 암시하는 장으로 1000쪽 분량의 지루함을 상당히 덜어준다. 


여러모로 노벨상을 받은 가치를 보여주는 소설




덤)

이 소설에서 1달러가 얼마의 가치를 지니는지 헷갈리는데, 대공황이 시작된 연도인 1929년의 1$ = 현재의 14.43$이다. 여기 에서 확인할 수 있다. 소설 배경이 정확히 몇 년도인지 알 수 없지만, 대공황이 배경인건 확실하므로 대략 1$ = 현재의 15$ 안팎이라고 생각하면 되겠다.

'' 카테고리의 다른 글

빛의 호위 - 조해진  (0) 2018.01.27
마음 - 나쓰메 소세키  (0) 2018.01.14
해가 지는 곳으로 - 최진영  (0) 2017.12.16
한계 비용 제로 사회 - 제레미 리프킨  (0) 2017.12.11
숙주인간 - 캐슬린 매콜리프  (0) 2017.12.11

+ Recent posts