2014-09-29 4 views
-1

다음은 C 프로그램의 한 기능입니다. 아래 함수에서 3 개의 char 포인터를 전달하고 있지만 함수에서 사용하지는 않습니다. 그러나 memset() 함수를 실행 한 후에는 문자열 값이 NULL 또는 GARBAGE가됩니다. 아무도 왜이 일이 일어 났는지 알려줄 수 있습니까?memset 설정 문자 포인터 NULL/쓰레기

여기 완전한 코드입니다 .... 제 테스트 코드로 잘못된 코딩 스타일을 무시하십시오 :).

#include <netinet/in.h> 
#include <stdio.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <netdb.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <strings.h> 
#include <unistd.h> 
#include <sys/poll.h> 


static void * process_request_client(void *arg); 
void getClientInput(int sockfd, char ** ptr_ip_addr, char ** ptr_port_no, char ** ptr_page); 
int split(char * str, char delim, char ***array, int *length); 
int connect_web(char * ip_addr, char * port, char * page); 
void process_webPage(int soc_client, int soc_web, char * page, char * host); 
//############## 

int main (int argc, char **argv) { 
    /* variables section */ 
    pthread_t tid; 
    int    listenfd, connfd; 
    pid_t    childpid; 
    socklen_t   clilen; 
    struct sockaddr_in cliaddr, servaddr; 

    /* creating a socket */ 
    if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 
    printf("\n%s: Error in socket", argv[0]); 
    exit(0); 
    } 

    /* configuring server address structure */ 
    bzero(&servaddr, sizeof(servaddr)); 
    servaddr.sin_family  = AF_INET; 
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    servaddr.sin_port  = htons(9876); 

    /* binding our socket to the service port */ 
    if (bind(listenfd, (struct sockaddr*) &servaddr, sizeof(servaddr)) < 0) { 
    printf("\n%s: Error in bind", argv[0]); 
    exit(0); 
    } 

    /* convert our socket to a listening socket */ 
    if (listen(listenfd, 5) < 0) { 
    printf("\n%s: Error in listen", argv[0]); 
    exit(0); 
    } 

    for (; ;) { 
    clilen = sizeof(cliaddr); 

    /* accept a new connection and return a new socket descriptor to 
    handle this new client */ 
    if ((connfd = accept(listenfd, (struct sockaddr*) &cliaddr, &clilen)) < 0) { 
     printf("\n%s: Error in accept", argv[0]); 
     exit(0); 
    } 

    pthread_create(&tid, NULL, &process_request_client, (void *) connfd); 
    } 
    return 0; 
} 


static void * process_request_client(void *soc_client) { 
    char * ip_addr; 
    char ** ptr_ip_addr; 
    char * port_no; 
    char ** ptr_port_no; 
    char * page; 
    char ** ptr_page; 

    ptr_ip_addr = &ip_addr; 
    ptr_port_no = &port_no; 
    ptr_page = &page; 

    int soc_web; 
    pthread_detach(pthread_self()); 

    getClientInput((int) soc_client,ptr_ip_addr,ptr_port_no,ptr_page); 

    printf("ip_addr in process_request_client -> %s \n port in process_request_client-> %s \n page in process_request_client->%s\n",ip_addr,port_no,page); 

    //create socket connection to web server 
    soc_web = connect_web(ip_addr, port_no, page); 

    printf("ip_addr in process_request_client -> %s \n port in process_request_client-> %s \n page in process_request_client->%s\n",ip_addr,port_no,page); 

    //process webPage 
    //process_webPage((int)soc_client, soc_web, page, ip_addr); 

    printf("ip_addr in process_request_client -> %s \n port in process_request_client-> %s \n page in process_request_client->%s\n",ip_addr,port_no,page); 

    close(soc_web); 
    close((int) soc_client); 
    return (NULL); 
} 

void getClientInput(int sockfd, char ** ptr_ip_addr, char ** ptr_port_no, char ** ptr_page){ 
    ssize_t n; 
    char line[512]; 
    char **res; 
    int rc, count = 0, k=0; 
    /* read from socket */ 
    n = read(sockfd, (void *) line, 512); 

    if (n < 0) { 
     printf("\nError in read"); 
     exit(0); 
    } else if (n == 0) { 
     return; 
    } 
    line[n-1] = NULL; 
    printf("Yo baby got it:%d\n",n); 
    //printf("%s\n",line); 
    //printf("####################################\n"); 


    //split it and store it variables 
    rc = split(line, ':', &res, &count); 
    if(rc) { 
    printf("Error: error in spliting \n"); 
    } 

    *ptr_ip_addr = res[0]; 
    *ptr_port_no = res[1]; 
    *ptr_page = res[2]; 
    printf("in getClientInput ->%s \n",*ptr_ip_addr); 
    printf("in getClientInput ->%s \n",*ptr_port_no); 
    printf("in getClientInput ->%s \n",*ptr_page); 
    //close(sockfd);     //closed here earlier 
} 

int split(char * str, char delim, char ***array, int *length) { 
    char *p; 
    char **res; 
    int count=0; 
    int k=0; 
    int index = 0; 

    do{ 
    //printf("%c\n", str[]); 
    index++; 
    } while (str[index] != NULL); 
    str[index] = ':'; 
    index++; 
    str[index] = NULL; 

    printf("%s--------------------------\n",str); 

    p = str; 
    // Count occurance of delim in string 
    while((p=strchr(p,delim)) != NULL) { 
    *p = 0; // Null terminate the deliminator. 
    p++; // Skip past our new null 
    count++; 
    } 

    // allocate dynamic array 
    res = calloc(1, count * sizeof(char *)); 
    if(!res) return -1; 

    p = str; 
    for(k=0; k<count; k++){ 
    if(*p) res[k] = p; // Copy start of string 
    p = strchr(p, 0); // Look for next null 
    p++; // Start of next string 
    } 

    *array = res; 
    *length = count; 

    return 0; 
} 

int connect_web(char * ip_addr_old, char * port_old, char * page_old) { 

    struct addrinfo hints, *res; 
    int sockfd, retVal; 
    char * ip_addr="www.website.edu"; 
    char * port ="80"; 

    printf("11111..ip_addr in connect_web 1 -> %s \n port in connect_web 2-> %s \n page in connect_web 3->%s\n",ip_addr_old,port_old,page_old); 


    printf("ip_addr in connect_web -> %s \n port in connect_web-> %s \n",ip_addr,port); 
    printf("size= %d\n",strlen(ip_addr)); 

    // first, load up address structs with getaddrinfo(): 
    memset(&hints, 0, sizeof hints); 
    printf("2222222.ip_addr in connect_web 1 -> %s \n port in connect_web 2-> %s \n page in connect_web 3->%s\n",ip_addr_old,port_old,page_old); 

    hints.ai_family = AF_UNSPEC; 
    hints.ai_socktype = SOCK_STREAM; 
    retVal=getaddrinfo(ip_addr, port, &hints, &res); 
    printf("getaddrinfo Return Val is -> %d\n",retVal); 
    // create a socket: 
    printf("33333333.ip_addr in connect_web 1 -> %s \n port in connect_web 2-> %s \n page in connect_web 3->%s\n",ip_addr_old,port_old,page_old); 

    sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 
    /* connecting to the server */ 
    //connect(sockfd, res->ai_addr, res->ai_addrlen); 
    printf("444444.ip_addr in connect_web 1 -> %s \n port in connect_web 2-> %s \n page in connect_web 3->%s\n",ip_addr_old,port_old,page_old); 

    if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0) { 
    printf("\n: Error in connect to web page"); 
    exit(0); 
    } 
    printf("55555.ip_addr in connect_web 1 -> %s \n port in connect_web 2-> %s \n page in connect_web 3->%s\n",ip_addr_old,port_old,page_old); 

    return sockfd; 

} 
void process_webPage(int soc_client, int soc_web, char * page, char * host){ 
    char arr[200]; 
    char * sendline; 
    char recvline[4096]; 
    int n,rv; 
    struct pollfd ufds[2]; 

    printf("\n%s----------in process_webPage\n",page); 
    printf("\n%s----------in process_webPage\n",host); 

    //ufds[0].fd = s1; 
    //ufds[0].events = POLLIN | POLLPRI; // check for normal or out-of-band 

    ufds[1].fd = soc_web; 
    ufds[1].events = POLLIN; // check for just normal data 

    // Prepare the HTTP request 
    sendline = arr; 
    strcpy(arr,"GET "); 
    strcat(arr,page); 
    strcat(arr," HTTP/1.1\r\nHost:"); 
    strcat(arr,host); 
    strcat(arr,"\r\n\r\n"); 


    /* send it to server */ 
    printf ("%s\n",sendline); 
    if (write(soc_web, (const void*) sendline, strlen(sendline)) < 0) { 
    printf("\n: Error in write to web server socket"); 
    exit(0); 
    } 


    // Receive data from Socket 
    rv = poll(ufds, 2, 3500); 
    /*while (rv > 0) { 
    if (rv == -1) { 
     perror("poll"); // error occurred in poll() 
    } else if (rv == 0) { 
     printf("Timeout occurred! No data after 3.5 seconds.\n"); 
    } else { 
     if (ufds[1].revents & POLLIN) { 
     recv(soc_web, recvline, 4096-1, 0); 
     } 
    } 
    //fputs(recvline, stdout); 
    printf("mmmmmmmmmmmmmmmmmmmm %d", rv); 
    rv = poll(ufds, 2, 3500); 
    }*/ 
    printf("@@@@@@@@@@@@ Out Side @@@@@@@@@@@\n"); 

    close(soc_web); 
} 

다음은 밖으로는 getClientInput 함수에 지역 변수입니다 char line[512];

Yo baby got it:37 
www.website.edu:80:/~page/index.html:-------------------------- 
in getClientInput ->www.website.edu 
in getClientInput ->80 
in getClientInput ->/~page/index.html 
ip_addr in process_request_client -> www.website.edu 
port in process_request_client-> 80 
page in process_request_client->/~page/index.html 
11111..ip_addr in connect_web 1 -> www.website.edu 
port in connect_web 2-> 80 
page in connect_web 3->/~page/index.html 
ip_addr in connect_web -> www.utdallas.edu 
port in connect_web-> 80 
size= 16 
2222222.ip_addr in connect_web 1 -> �q�website.edu 
port in connect_web 2-> 80 
page in connect_web 3->/ 
getaddrinfo Return Val is -> 0 
33333333.ip_addr in connect_web 1 -> 
port in connect_web 2-> 
page in connect_web 3-> 
444444.ip_addr in connect_web 1 -> 
port in connect_web 2-> 
page in connect_web 3-> 
55555.ip_addr in connect_web 1 -> �q�webs�PS�`PS� 
port in connect_web 2-> 
page in connect_web 3-> 
ip_addr in process_request_client -> �q�webs�PS�`PS� 
port in process_request_client-> 
page in process_request_client-> 
ip_addr in process_request_client -> �q�webs�PS�`PS� 
port in process_request_client-> 
page in process_request_client-> 
+1

인쇄물을 붙여 넣을 수 있습니까? –

+0

왜 struct-initializer를 직접 사용하지 않고'memset'을 사용하고 이후에'hints'의 일부 멤버를 수동으로 설정하고 컴파일러가 한번에 모든 작업을 수행하게합니까? 더 짧고 훨씬 더 읽기 쉬울 것입니다 ... – Deduplicator

+1

옆으로 : 적당한 길이를 유지하십시오. 당신은 정말로 80 문자보다 긴 줄을 필요로하지 않습니다! 가로 스크롤은 치명적입니다. – Deduplicator

답변

1

귀하의 포인터 ip_addr, port_no, page 모든 가리키는을 넣어이다. 이 함수가 메모리를 해제하면 반환됩니다.

connect_web의 현상은 해당 메모리가 connect_web 내부의 로컬 변수에 다시 사용 되었기 때문에 발생합니다. 해당 로컬 변수를 수정하면 포인터가 가리키는 char line[512]의 내용이 변경된 것처럼 보입니다.

이 문제를 해결하려면 static char line[512];으로 만들거나 getClientInput 함수가 "반환 중"인 문자열 각각에 동적으로 메모리를 할당하도록 할 수 있습니다.

그러나 코드가 이미 꽤 복잡하고 따라하기가 어렵지만 메모리 오류가 있다는 것은 놀라운 일이 아닙니다. 모든 포인터를 포함하는 struct을 작성하는 것이 좋습니다 (ad hoc 배열 3 개 포인터 또는 함수 매개 변수 목록). 하나의 구조체 인스턴스에 대해 모든 것을 할당했는지 확인하십시오. 장소. 그렇다면 일단 구조체 전체를 해제하는 단일 함수를 가질 수 있습니다.

+0

또한, getClientInput은'res [0]','res [1]','res [2]'에 접근하기 전에'count> = 3'을 검사해야합니다. –

+0

@MattMcNabb에 감사드립니다. 모든 포인터와 포인터에 대한 포인터. 대신 process_request_client() 내부의 구조를 사용하여 필요한 함수에 전달했습니다. – bhakta288