次のページ 前のページ 目次へ

Linux C HOWTO

Yoshio Shimamura <yoshios@green.ocn.ne.jp>

v1.0, 26 September 2000
この文書は、LinuxにおけるC言語の HOWTO です。ここでは、基本的用法やお約束事について記述しています。文法等C言語の基本については、K&R等を参照してください。 この文書の最新版は http://hp.vector.co.jp/authors/VA004572/index.html から入手可能です。

Index

1 基礎知識
1.1 プログラムの配置
1.2 ヘッダーファイル
1.3 ライブラリ
2 基本的なプログラムの作成
3 変数操作
3.1 掛け合わせて123456789になる2つの5桁の数を求める
3.2 1から100までの素数を求める
4 ファイル操作
5 ディレクトリ操作
6 文字列操作
6.1 トークン分解
6.2 ファイル内の指定文字列を含む行と一致数を表示
7 エスケープシーケンス
8 インターネット
8.1 指定したホストのポート80に接続するTCP/IPクライアント
8.2 指定したホストの指定ポートに文字列を送信するTCP/IPクライアント

1 基礎知識

1.1 プログラムの配置

Linuxにおける実行プログラムは、次のように配置されます。
/usr/bin
システムが提供した汎用プログラム
/usr/local/bin
スーパーユーザが追加したローカルネットワークを対象としたプログラム
ユーザが個人的に作成したプログラムは、通常 ~/bin などに格納して、そのディレクトリにコマンドパスを通しておきます。

1.2 ヘッダーファイル

標準のヘッダーファイルの場所
/usr/include
system依存ヘッダーの場所
/usr/include/sys
Linux依存ヘッダーの場所
/usr/include/linux
X Window System関連ヘッダーの場所
/usr/include/X11
GNU C++ヘッダーの場所
/usr/include/g++
コンパイラに標準以外のディレクトリにあるヘッダーファイルを追加使用するよう指示するには、-Iフラグを使う。
$ gcc -I/usr/openwin/include -o hoge hoge.c

2 ライブラリ

標準システムライブラリの場所
/lib
/usr/lib
ライブラリをコンパイラに追加指定するには、フルパスで指定するか、-lフラグを使う。
$ gcc -o hoge hoge.c /usr/lib/libpng.so
$ gcc -o hoge hoge.c -lpng
ライブラリ検索ディレクトリを追加指定する場合には、-Lフラグを使用する。
$ gcc -o hoge -L/hoge/foo/mylib hoge.c -lmisc

2 基本的なプログラムの作成

3 変数操作

3.1 掛け合わせると123456789になる2つの5桁の数を求める

int a, b, c;

for (a = 10000; a < 100000; a++) {
  for (b = 10000; b < 100000; b++) {
    c = a * b;
    if (c == 123456789) {
      printf("%d x %d = %d\n", a, b, c);
      break;
    }
  }
}

3.2 1から100までの素数を求める

int i, j;
float m;
int flag;

for (i = 100; i > 1; i++) {
  flag = 0;
  j = i;
  while (j > 1) {
    if ((m = (i % j)) == 0.0) flag++;
    j--;
  }
  if (flag == 1) printf("%d\n", i);
}

4 ファイル操作

ファイルを行単位で処理しコピーする

#include <stdio.h>

int main(int argc, char *argv[])
{
  FILE *src, *dst;
  char lbuf[BUFSIZ];

  if (argc != 3) {
    fprintf(stderr, "Usage: %s source-file destination-file\n", *argv);
    exit(1);
  }

  if ((src = fopen(argv[1], "r")) == NULL) {
    perror(argv[1]);
    exit(1);
  }

  if ((dst = fopen(argv[2], "a")) == NULL) {
    perror(argv[2]);
    exit(1);
  }

  while (fgets(lbuf, BUFSIZ, src) != NULL) {
    fputs(lbuf, dst);
  }

  fclose(src);
  fclose(dst);
  return 0;
}

5 ディレクトリ操作

指定ディレクトリを走査し存在するファイル名を得る

/*
 * dl.c
 * Yoshio Shimamura 2000
 */
#include <unistd.h>
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>

void dir_list(char *dir)
{
  DIR *dp;
  struct dirent *ent;
  struct stat statbuf;

  if ((dp = opendir(dir)) == NULL) {
    fprintf(stderr, "cannot open: %s\n", dir);
    return;
  }

  chdir(dir);

  while ((ent = readdir(dp)) != NULL) {
    stat(ent->d_name, &statbuf);
    if (S_ISDIR(statbuf.st_mode)) continue;
    else printf("%s\n", ent->d_name);
  }
  
  chdir("..");
  closedir(dp);
}

int main(int argc, char **argv)
{
  dir_list(argv[1]);

  exit(0);
}

6 文字列操作

6.1 トークン分解

慎重に用いないと危険だが、移植性の高いstrtokを用いると次のようになる。
#include <stdio.h>
#include <string.h>

int main(int argc, chat **argv)
{
  char data[] = "Goto Maki,Abe Nacci";
  char *delim = ",";
  char *str;

  str = strtok(data, delim);
  printf("1 = %s\n", str);

  str = strtok(NULL, delim);
  printf("2 = %s\n", str);

  return 0;
}
安全バージョンであるstrsepを用いると次のようになる。
#include <stdio.h>
#include <string.h>

int main(int argc, chat **argv)
{
  char data[] = "Yaguchi Mari,Tsuji Nozomi";
  char *delim = ",";
  char *str;
  char **p;

  *p = data;
  str = strsep(p, delim);
  printf("1 = %s\n", str);

  str = strsep(p, delim);
  printf("2 = %s\n", str);

  return 0;
}

6.2 ファイル内の指定文字列を含む行と一致数を表示

#include <stdio.h>
#include <string.h>

int ys_sfs(char *fname, char *str)
{
  FILE *fp;
  char line[BUFSIZ];
  int count;

  if ((fp = fopen(fname, "r")) == NULL) {
    perror(fname);
    exit(1);
  }

  count = 0;
  while (fgets(line, BUFSIZ, fp) != NULL) {
    if (NULL != strstr(line, str)) {
      count++;
      printf("%s", line);
    }
  }

  fclose(fp);
  return count;
}

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

  if (argc != 3) {
    printf("Usage: %s file string\n", argv[0]);
    exit(1);
  }

  count = ys_sfs(argv[1], argv[2]);
  printf("%d\n", count);

  return 0;
}

7 エスケープシーケンス

エスケープシーケンスによる表示色、表示位置の指定

#include <stdio.h>

#define ESC_BLACK "\033[0m"
#define ESC_RED "\033[31m"
#define ESC_GREEN "\033[32m"
#define ESC_YELLOW "\033[33m"
#define ESC_BLUE "\033[34m"
#define locate(x,y) printf("\033[%d;%dH", y, x)

int main()
{
  locate(5,10);
  printf(ESC_BLUE);
  printf("Hello\n");
  printf(ESC_BLACK);
}

8 インターネット

8.1 指定したホストのポート80に接続するTCP/IPクライアント

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
  char hostname[64];
  struct hostent *hp;
  int sock;
  struct sockaddr_in sin;

  /* hostname? */
  gethostname(hostname, sizeof(hostname));
  printf("Hostname: %s\n", hostname);

  /* get hostentry */
  if ((hp = gethostbyname(hostname)) == NULL) {
    fprintf(stderr, "%s: unknown host.\n", hostname);
    exit(1);
  }

  /* socket */
  if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    perror("Client: socket");
    exit(1);
  }

  /* Create address to */
  sin.sin_family = AF_INET;
  sin.sin_port = htons(80);
  bcopy(hp->h_addr, &sin.sin_addr, hp->h_length);

  /* connect */
  if (connect(sock, &sin, sizeof(sin)) < 0) {
    perror("client: connect");
    exit(1);
  }
}

8.2 指定したホストの指定ポートに指定文字列を送信するTCP/IPクライアント

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h> /* atoi */

#define DEBUG

int readn(register int fd, register char *ptr, register int nbytes)
{
  int nleft, nread;

  nleft = nbytes;
  while (nleft > 0) {
    nread = read(fd, ptr, nleft);
    if (nread < 0) return(nread);
    else if (nread == 0) break;
    nleft -= nread;
    ptr += nread;
  }
  return (nbytes - nleft);
}

int writen(register int fd, register char *ptr, register int nbytes)
{
  int nleft, nwritten;

  nleft = nbytes;
  while (nleft > 0) {
    nwritten = write(fd, ptr, nleft);
    if (nwritten <= 0) return (nwritten);
    nleft -= nwritten;
    ptr += nwritten;
  }
  return (nbytes - nleft);
}

int readline(register int fd, register char *ptr, register int maxlen)
{
  int n, rc;
  char c;

  for (n = 1; n < maxlen; n++) {
    if ((rc = read(fd, &c, 1)) == 1) {
      *ptr++ = c;
      if (c == '\n') break;
    } else if (rc == 0) {
      if (n == 1) return (0);
      else break;
    } else return (-1);
  }
  *ptr = 0;
  return (n);
}

/*------------------------------------------------------
 * This is the main function of sendline
 * Parameters:
 * argv[1] = IP Address of target host.
 * argv[2] = Portnumber of service
 * argv[3] = Strings
------------------------------------------------------*/
int main(int argc, char *argv[])
{
  int socks;
  struct sockaddr_in saddr;
  struct in_addr ip;
  int ret;
  char str[2048];
  int len;

  if (argc < 3) {
    perror("bad args");
    exit(1);
  }

#ifdef DEBUG
  printf("target host = %s\n", argv[1]);
  printf("service port = %s\n", argv[2]);
  printf("command = %s\n", argv[3]);
#endif  

  socks = socket(PF_INET, SOCK_STREAM, 0);

  saddr.sin_family = AF_INET;
  /* saddr.sin_addr.s_addr = inet_addr("127.0.0.1"); */
  inet_aton(argv[1], &ip);
  saddr.sin_addr.s_addr = ip.s_addr;
  saddr.sin_port = htons(atoi(argv[2]));
  /* saddr.sin_port = htons(80); */

  ret = connect(socks, (struct sockaddr *)&saddr, sizeof(saddr));

  if (ret == -1) {
    perror("oops: client1");
    exit(1);
  } else {
    printf("success: connect\n");
  }

  /* send data */
  len = writen(socks, argv[3], sizeof(argv[3]));
  readn(socks, str, sizeof(str));
 
  close(socks);
  exit(0);
}

次のページ 前のページ 目次へ