list = (NODE *)malloc (sizeof(NODE));
list -> data = 'a';
list -> next = (NODE*)malloc (sizeof(NODE));
list -> next -> data = 'b';
list -> next -> next = (NODE*)malloc (sizeof(NODE));
list -> next -> next -> data = 'c';
list -> next -> next -> next = NULL;
list = (NODE *) malloc (sizeof (NODE)); // line #2
list -> data = 'a'; // line #3
temp = list; // line #4
temp -> next = (NODE *) malloc (sizeof (NODE)); // line #5
temp = temp -> next; // line #6
temp -> data = 'b'; // line #7
temp -> next = (NODE *) malloc (sizeof (NODE)); // line #8
temp = temp -> next; // line #9
temp -> data = 'c'; // line #10
//=================================================================
((NODE *)(0X08049700)) -> data = 'd'; // EX
//====================================================================
temp -> next = NULL; // line #11
printf("%08X\n", temp); // temp의 주소 // 연결리스트의 출력
temp = list; while(temp != NULL)
{
printf("%5c\n", temp -> data);
temp = temp -> next;
}
return 0;
}
소스를 분석해 보면 line#2에 해당하는 부분은 동적할당을 하는 부분이다. 이때 list는 NODE사이즈 크기 8바이트 만큼의 메모리의 주소를 가르키는 것이다. temp의 크기는 4바이트(포인터) 이지만 이 포인터가 가르키는 곳의 크기는 8바이트이다.
line#4 는 포인터를 복사한다고 생각하면 된다. 포인터 변수에 포인터 변수의 값을 그대로 넘겨주기때문에 둘다 같은 곳을 가르키게 된다.
line#5 는 동적할당으로 또 메모리를 확보한다.
line#6 에서 temp = temp->next 라는 것은 temp가 가르키는 구조체 형식에서 next로 가서 temp에 넣으라는 명령이다. 이것을 그림으로 보면
로 되는 것이다.
line#10을 그림으로 보면
된다.
이제 이것을 출력을 하면 아래와 같이 나온다.
10-4 의 출력 결과이다. 출력된 결과는
((NODE *)(0X08049700)) -> data = 'd'; 을 적었을때와 적지 않았을때의 결과이다.
temp의 주소가 위에 보이는 0X08049700 이다. temp가 주소를 가지고 있는 포인터이기 때문에 포인터대신 주소값을 바로 알려주면 따라갈수 있을것이다. 그런데 이때 주소만을 적으면 상수에 상수값이 대입되는 결과가 된다. 상수에 상수는 오류가 된다. 그래서 주소를 캐스팅 시켜줘야 한다. 포인터의 타입과 같은 타입으로 캐스팅을 시켜 주면 주소를 입력해도 같은 결과를 가진다.
만약 int A; 가 있다고 가면 A의 주소는 1000이라 할때 주소가 100을 가지게 코드를 적는다면?
*((int *)(1000)) = 100; 이된다. 주소를 가지는 int형 포인터로 캐스팅을 해주고 따라가게 한다면 A를 출력할때 100이 출력이 된다. 하지만 컴파일할때마다 변수의 주소값이 변한다면 이방법은 쓸수 없다.
예제 10-4의 소스에서는 free()함수가 빠져 있다. free함수는 동적할당을 하는malloc 함수에 사용된 메모리를 반환해주는 함수로 free로 반환을 하지 않으면 동적할당에 사용된 메모리가 자동으로 반환되지 않아 메모리 손실을 가져 오게 된다. 동적할당을 사용한 후에는 꼭 free() 함수를 사용해서 메모리를 반환해 주어야 한다.
malloc은 heap의 메모리 주소를 알려주는 역할을 한다.
malloc이 반환할때에 heap의 주소를 한번 알려준다. 이때 malloc의 반환된 값을 위의 소스에서 보면 list가 받는데 list를 삭제시키면 반환값을 한번 알려줬기 때문에 다시 알수가 없다. 이렇게 되면 메모리가 할당은 되었지만 어딘지 알수 없게 된다.
다음은 LCD의 연결법이다.
lcd 모듈에서 보면 빨간색으로 표시된 부분은 LCD의 밝기를 조절할수 있도록 하는 부분으로 가변저항을 써서 밝기를 조절가능하다.
이 그림은 LCD와 ARM의 연결 을 보여주는 그림이다. BUS를 연결시킨 그림을 보여준다.
int main()
{ int sock; int snd_buf = 500; int rcv_buf = 1000;
int state;
socklen_t len;
sock = socket(PF_INET, SOCK_STREAM, 0);
// 입출력 버퍼 크기 설정
state = setsockopt(sock, SOL_SOCKET, SO_RCVBUF,&rcv_buf,sizeof(rcv_buf)); if(state)
error_handling("setsockopt() error ");
state = setsockopt(sock, SOL_SOCKET, SO_SNDBUF,&snd_buf,sizeof(snd_buf)); if(state)
error_handling("setsockopt() error ");
// 입출력 버퍼 크기 확인
len = sizeof(rcv_buf);
state = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcv_buf, &len); if(state)
error_handling("getsockopt() error ");
len = sizeof(snd_buf);
state = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &snd_buf, &len); if(state)
error_handling("getsockopt() error ");
printf("데이터 입력받기 위한 소켓의 버퍼 크기 : %d \n", rcv_buf);
printf("데이터 출력받기 위한 소켓의 버퍼 크기 : %d \n", snd_buf);
여기에서는 setsockopt함수를 사용했다. 이 함수는 소켓옵션의 값을 지정할 수 있다. 보면 500과 1000으로 지정을 하였다. 이제 바꼈는지 확인을 위해 처음소스와 함께 출력을 해본 결과는
처을 읽어온 버퍼의 크기와 500과 1000으로 변경한 결과이다. 여기서 보면 set으로 지정한 값이 나오지 않았다. 이것은 함수에 전달된 값이 항상 소켓 버퍼의 새로운 크기로 적용되지 않는다는 사실이다. 우리가 입력한 값은 사용자가 시스템에게 '이값을 한다'라고 알려주는 일종의 '힌트'로 생각하면된다.
사용자의 리소스를 관리하는것은 결국 시스템의 몫이며 소켓 버퍼 크기의 조정을 할 때 다른 부분들도 고려하기 때문에 사용자가 지정한 값이 꼭 뜨는것은 아니다.
시그널은 어떤 이벤트가 발생했을 때 운영체제가 프로그램에 이를 알리는 기법이다. 이러한 이벤트의 예로 사용자가 입력한 인터럽트 문자 혹은 타이머가 종료된 경우를 들 수 있다. 다음은 시그널에 대한 기본동작을 바꿀 수 있는 함수이다.
int my_signal(); // 새로운 시그널 처리함수 선언 int count = 0; //ctrl-C 입력 횟수 카운터
int main()
{ int i =0; struct sigaction act; // sigaction구조체 변수
act.sa_handler = my_signal; // 시그널 처리함수 지정
sigemptyset(&act.sa_mask); // sm_mask의 모든 비트를 0으로 설정
act.sa_flags = 0;