Przejdź do zawartości

C++/Map

Z Wikibooks, biblioteki wolnych podręczników.
< C++

Opis

[edytuj]

Mapa to posortowany kontener asocjacyjny, czyli zbiornik o zmiennej długości gromadzący dane, które można dodawać i usuwać. Nie można jednak dodawać danych na konkretną pozycję, ponieważ kolejność ustalana jest według danego klucza. Mapa jest również parowym zbiornikiem asocjacyjnym, czyli jej elementami są pary wartości klucz i dana. Pierwszej wartości key_type, czyli klucza mapy, nie można zmieniać, natomiast druga wartość danej jest przypisywalna (np.(*i).second=2). Mapa jest w końcu unikalnym kontenerem asocjacyjnym, co oznacza, że każde dwa elementy mają różny klucz.

Mapa zdefiniowana jest w standardowym nagłówku map oraz w niestandardowym, wstecznie kompatybilnym nagłówku map.h.

Przykład

[edytuj]
#include<iostream>
#include<map>
using namespace std;

int main()
{
   map<int, string> tydzien;
   tydzien[1] = "niedziela";
   tydzien[2] = "poniedzialek";
   tydzien[3] = "wtorek";
   tydzien[4] = "sroda";
   tydzien[5] = "czwartek";
   tydzien[6] = "piatek";
   tydzien[7] = "sobota";

   cout << "trzeci dzien tygodnia:  " << tydzien[3] << '\n';

   map<int, string>::iterator cur;

   // zwrocenie elementu o kluczu 3
   cur = tydzien.find(3);

   // elementy o kluczach większych i mniejszych
   map<int, string>::iterator prev = cur;
   map<int, string>::iterator next = cur;    
   ++next;
   --prev;

   cout << "Wczesniejszy:  " << prev->second << '\n';
   cout << "Nastepny:  " << next->second << '\n';
}

mmap

[edytuj]

Funkcja w c/c++, która allokuje pamięć tak jak malloc. APUE zaleca używanie mmap dla alokowania dużych ilości pamięci, bo może to być zauważalnie szybsze od malloc. Jako programiści zwykle używamy funkcji malloc (), free () i podobnych do przydzielania pamięci. Są one dostarczane przez bibliotekę glibc (). Rzeczywista praca jest wykonywana przez mmap () i munmap (), który jest wywołaniem systemowym Linuksa. Funkcja mmap () lub wywołanie systemowe utworzy mapowanie w wirtualnej pamięci bieżącego procesu. Przestrzeń adresowa składa się z wielu stron, a każdą stronę można zmapować jakimś zasobem. Możemy utworzyć mapowanie dla zasobów, których chcemy użyćFunkcje mmap () i munmap () są dostarczane przez bibliotekę sys / mman.h. więc w celu użycia musimy je uwzględnić, jak poniżej.

  1. include <sys / mman.h>

void * mmap (void * addr, size_t lengthint "prot", int "flags,

           int fd, off_t offset)
 void * addr to adres, od którego chcemy rozpocząć mapowanie
 size_t lengthint to rozmiar, który chcemy zmapować jako liczbę całkowitą
 PROT_READ | PROT_WRITE | PROT_EXEC opcje dotyczące strony
 MAP_ANON | MAP_PRIVATE opcje dotyczące stronyWe have two option about memory mapping for sharing.

Mamy dwie opcje dotyczące mapowania pamięci do udostępniania.

MAP_SHARED zmapuje daną stronę i będzie to widoczne również w innych procesach. MAP_PRIVATE zmapuje daną stronę i nie będzie to widoczne dla innych procesów.

Przykład

[edytuj]
/* 
 * tiny.c - a minimal HTTP server that serves static and
 *          dynamic content with the GET method. Neither 
 *          robust, secure, nor modular. Use for instructional
 *          purposes only.
 *          Dave O'Hallaron, Carnegie Mellon
 *trochę ten kod przerobiłem ale nie wiele
 *  thc
 *          usage: tiny <port>
 */

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <fcntl.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define BUFSIZE 1024
#define MAXERRS 16

extern char **environ; /* the environment */

/*
 * error - wrapper for perror used for bad syscalls
 */
void error(char *msg) {
  perror(msg);
  exit(1);
}

/*
 * cerror - returns an error message to the client
 */
void cerror(FILE *stream, char *cause, char *errno, 
	    char *shortmsg, char *longmsg) {
  fprintf(stream, "HTTP/1.1 %s %s\n", errno, shortmsg);
  fprintf(stream, "Content-type: text/html\n");
  fprintf(stream, "\n");
  fprintf(stream, "<html><title>Tiny Error</title>");
  fprintf(stream, "<body bgcolor=""ffffff"">\n");
  fprintf(stream, "%s: %s\n", errno, shortmsg);
  fprintf(stream, "<p>%s: %s\n", longmsg, cause);
  fprintf(stream, "<hr><em>The Tiny Web server</em>\n");
}

int main(int argc, char **argv) {

  /* variables for connection management */
  int parentfd;          /* parent socket */
  int childfd;           /* child socket */
  int portno;            /* port to listen on */
  int clientlen;         /* byte size of client's address */
  struct hostent *hostp; /* client host info */
  char *hostaddrp;       /* dotted decimal host addr string */
  int optval;            /* flag value for setsockopt */
  struct sockaddr_in serveraddr; /* server's addr */
  struct sockaddr_in clientaddr; /* client addr */

  /* variables for connection I/O */
  FILE *stream;          /* stream version of childfd */
  char buf[BUFSIZE];     /* message buffer */
  char method[BUFSIZE];  /* request method */
  char uri[BUFSIZE];     /* request uri */
  char version[BUFSIZE]; /* request method */
  char filename[BUFSIZE];/* path derived from uri */
  char filetype[BUFSIZE];/* path derived from uri */
  char cgiargs[BUFSIZE]; /* cgi argument list */
  char *p;               /* temporary pointer */
  int is_static;         /* static request? */
  struct stat sbuf;      /* file status */
  int fd;                /* static content filedes */
  int pid;               /* process id from fork */
  int wait_status;       /* status from wait */

  /* check command line args */

  portno = 80;

  /* open socket descriptor */
  parentfd = socket(AF_INET, SOCK_STREAM, 0);
  if (parentfd < 0) 
    error("ERROR opening socket");

  /* allows us to restart server immediately */
  optval = 1;
  setsockopt(parentfd, SOL_SOCKET, SO_REUSEADDR, 
	     (const void *)&optval , sizeof(int));

  /* bind port to socket */
  bzero((char *) &serveraddr, sizeof(serveraddr));
  serveraddr.sin_family = AF_INET;
  serveraddr.sin_addr.s_addr = inet_addr("127.0.0.2");
  serveraddr.sin_port = htons((unsigned short)portno);
  if (bind(parentfd, (struct sockaddr *) &serveraddr, 
	   sizeof(serveraddr)) < 0) 
    error("ERROR on binding");

  /* get us ready to accept connection requests */
  if (listen(parentfd, 5555) < 0) /* allow 5 requests to queue up */ 
    error("ERROR on listen\n");

  /* 
   * main loop: wait for a connection request, parse HTTP,
   * serve requested content, close connection.
   */
  clientlen = sizeof(clientaddr);
  while (1) {

    /* wait for a connection request */
    childfd = accept(parentfd, (struct sockaddr *) &clientaddr, &clientlen);
    if (childfd < 0) 
      error("ERROR on accept");
    
    /* determine who sent the message */
    hostp = gethostbyaddr((const char *)&clientaddr.sin_addr.s_addr, 
			  sizeof(clientaddr.sin_addr.s_addr), AF_INET);
    if (hostp == NULL)
      error("ERROR on gethostbyaddr");
    hostaddrp = inet_ntoa(clientaddr.sin_addr);
    if (hostaddrp == NULL)
      error("ERROR on inet_ntoa\n");
    
    /* open the child socket descriptor as a stream */
    if ((stream = fdopen(childfd, "r+")) == NULL)
      error("ERROR on fdopen");

    /* get the HTTP request line */
    fgets(buf, BUFSIZE, stream);
    printf("%s", buf);
    sscanf(buf, "%s %s %s\n", method, uri, version);

    /* tiny only supports the GET method */
    if (strcasecmp(method, "GET")) {
      cerror(stream, method, "501", "Not Implemented", 
	     "Tiny does not implement this method");
      fclose(stream);
      close(childfd);
      continue;
    }

    /* read (and ignore) the HTTP headers */
    fgets(buf, BUFSIZE, stream);
    printf("%s", buf);
    while(strcmp(buf, "\r\n")) {
      fgets(buf, BUFSIZE, stream);
      printf("%s", buf);
    }

    /* parse the uri [crufty] */
    if (!strstr(uri, "cgi-bin")) { /* static content */
      is_static = 1;
      strcpy(cgiargs, "");
      strcpy(filename, ".");
      strcat(filename, uri);
      if (uri[strlen(uri)-1] == '/') 
	strcat(filename, "index.html");
    }
  
      else {
	strcpy(cgiargs, "");      
      strcpy(filename, ".");
      strcat(filename, uri);
    }

    /* make sure the file exists */
    if (stat(filename, &sbuf) < 0) {
      cerror(stream, filename, "404", "Not found", 
	     "Tiny couldn't find this file");
      fclose(stream);
      close(childfd);
      continue;
    }

    /* serve static content */
    if (is_static) {
      if (strstr(filename, ".html"))
	strcpy(filetype, "text/html");
      else if (strstr(filename, ".gif"))
	strcpy(filetype, "image/gif");
      else if (strstr(filename, ".jpg"))
	strcpy(filetype, "image/jpg");
      else 
	strcpy(filetype, "text/plain");

      /* print response header */
      fprintf(stream, "HTTP/1.1 200 OK\n");
      fprintf(stream, "Server: Tiny Web Server\n");
      fprintf(stream, "Content-length: %d\n", (int)sbuf.st_size);
      fprintf(stream, "Content-type: %s\n", filetype);
      fprintf(stream, "\r\n"); 
  fflush(stream);

      /* Use mmap to return arbitrary-sized response body */
      fd = open(filename, O_RDONLY);
void*  p=mmap(0, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
      fwrite(p, 1, sbuf.st_size, stream);
      munmap(p, sbuf.st_size);
    }

    /* serve dynamic content */
    else {
      /* make sure file is a regular executable file */
      if (!(S_IFREG & sbuf.st_mode) || !(S_IXUSR & sbuf.st_mode)) {
	cerror(stream, filename, "403", "Forbidden", 
	       "You are not allow to access this item");
	fclose(stream);
	close(childfd);
	continue;
      }

      /* a real server would set other CGI environ vars as well*/
      setenv("QUERY_STRING", cgiargs, 1); 
      /* print first part of response header */
      sprintf(buf, "HTTP/1.1 200 OK\r\n");
   
      sprintf(buf, "Server: Tiny Web Server\r\n");

      /* create and run the child CGI process so that all child
         output to stdout and stderr goes back to the client via the
         childfd socket descriptor */
      pid = fork();
      if (pid < 0) {
	perror("ERROR in fork");
	exit(1);
      }
      else if (pid > 0) { /* parent process */
	wait(&wait_status);
      }
      else { /* child  process*/
	close(0); /* close stdin */
	dup2(childfd, 1); /* map socket to stdout */
	dup2(childfd, 2); /* map socket to stderr */
	if (execve(filename, NULL, environ) < 0) {
	  perror("ERROR in execve");
	}
      }
    }
   /* clean up */
    fclose(stream);
    close(childfd);
  }
}