[C++/C] mapとは

mapはvector同様、配列の一種。
vectorが要素へのアクセスを0, 1, 2…といったインデックスで行っている一方、mapはキーが要素隣、連想配列とも言われる。

#include <iostream>
#include <string>
#include <map>

using namespace std;

int main() {
    map <string, int> score;
    string names[] = {"Tom", "Bob", "Mike"};
    score[names[0]] = 100;
    score[names[1]] = 80;
    score[names[2]] = 120;
    int i;
    for(i = 0; i < 3; i++){
        cout << names[i] << ":" << score[names[i]] << endl;
    }
    return 0;
}

$ g++ -o sample sample.cpp && ./sample
Tom:100
Bob:80
Mike:120

[C++/C] external宣言

C言語において、extern宣言はグローバル変数を共有する仕組み

グローバル変数とローカル変数

#include <stdio.h>

int gNumber = 100;

void func(void) {
    gNumber += 100;
}

int main(void) {
    int tmp = 100;

    func();

    printf("tmp : %d\n", tmp);
    printf("gNumber : %d\n", gNumber);
}

$ gcc test.c -o test && ./test
tmp : 100
gNumber : 200

複数ファイルにする
main.c

#include <stdio.h>

void func();

int main(void) {

    func();
    printf("gNumber : %d\n", gNumber);
}

sub.c

int gNumber = 100;

void func(void) {
    gNumber += 100;
}

この場合、sub.cのコンパイルは通るがmain.cのコンパイル時にgNumberが定義されていない識別子としてエラーになる。
$ gcc -c sub.c
$ gcc -c main.c
main.c: In function ‘main’:
main.c:8:30: error: ‘gNumber’ undeclared (first use in this function)
8 | printf(“gNumber : %d\n”, gNumber);
| ^~~~~~~
main.c:8:30: note: each undeclared identifier is reported only once for each function it appears in

そこでmain.cでexternで宣言する

#include <stdio.h>

extern int gNumber;
void func();

int main(void) {

    func();
    printf("gNumber : %d\n", gNumber);
}

$ gcc -c main.c
$ gcc main.o sub.o -o main
$ ./main
gNumber : 200

[C++ basic] 出力, 文字数字

#include <iostream>
using namespace std;

int main() {
    cout << "ようこそC++!\n";
    cout << "lets start c++!\n";

    return 0;
}

coutはstandard outputと結び付けられ、 は表示を意味する
iostreamは画面出力の機能などを表す
coutは本来、using namespace stdでstc.coutと書くが、省略もできる。

int main() {
    cout << 1 << 2 << 3 << '\n' << 4 << 5 << '\n';

    return 0;
}

c++では文字、数字の表記をリテラルと呼ぶ。リテラルの他に、キーワード、識別子、演算子、区切り子などがある。
リテラルは”で囲む

#include <iostream>
using namespace std;

int main() {
    cout << 'A' << '\n';
    cout << "welcome to C++!\n";
    cout << 123 << '\n';

    return 0;
}

エスケープシーケンス

int main() {

    cout << "円記号を表示する:" << '\\' << '\n';
    cout << "アポストロフィを表示する:" << '\'' << '\n';

    return 0;
}

$ g++ -o sample sample.cpp && ./sample
円記号を表示する:\
アポストロフィを表示する:’

文字コード

int main() {

    cout << "8進数101の文字コードを持つ文字は" << '\101' << "です\n";
    cout << "16進数61の文字コードを持つ文字は" << '\x61' << "です\n";

    return 0;
}

$ g++ -o sample sample.cpp && ./sample
8進数101の文字コードを持つ文字はAです
16進数61の文字コードを持つ文字はaです

文字リテラルは”でくくる。
数値には整数と浮動小数点があり、それぞれinteger literal, floating literalと呼ぶ

int main() {

    cout << "10進数の10は" << 10 << "です\n";
    cout << "8進数の10は" << 010 << "です\n";
    cout << "16進数の10は" << 0x10 << "です\n";
    cout << "16進数のFは" << 0xF << "です\n";

    return 0;
}

$ g++ -o sample sample.cpp && ./sample
10進数の10は10です
8進数の10は8です
16進数の10は16です
16進数のFは15です

int main() {

    cout <<  123 << '\n';
    cout << "\\" << "100もらった\n";
    cout << "また明日\n";

    return 0;
}

8進数と16進数

#include <iostream>
using namespace std;

int main() {

    // 8進数
    cout <<  06 << '\n';
    cout <<  024 << '\n';
    cout <<  015 << '\n';

    // 16進数
    cout <<  0x6 << '\n';
    cout <<  0x14 << '\n';
    cout <<  0xd << '\n';
}

16進数はビットコインで基本となってますね。

Ubuntu22.04でc++の実行環境を作る

$ sudo apt install build-essential
$ gcc –version
gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ g++ –version
g++ (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

#include <iostream>
using namespace std;

int main() {
    cout << "ようこそC++!\n";

    return 0;
}

$ g++ -o sample sample.cpp && ./sample
ようこそC++!

configureの作成

cc コンパイラオプション
% cc [<オプション>] <ファイル名> [<ライブラリ>]

srcdir: コンパイルされるソースに対するディレクトリ
.ac: ユーザーのアクセス権限を証明

#!/bin/bash
cat >>Makefile.am <

# ビルドしてインストール
bin_PROGRAMS=test

#コンパイルする際のコンパイルオプション
#../configureなどルートディレクトリ以外で実行した時のインクルードディレクトリ
test_CFLAGS=-g -l @srcdir@/include/

#test_LDADDはライブラリ
test_LDADD= -lm

#ソースコード
test_SOURCES=test.c 

#ライブラリ用設定
include_HEADERS=test.h 
#ライブラリ作成する際のライブラリ名
lib_LIBRARIES=libtest.a 
#libtest.aのソースコード
libtest_a_SOURCES

#ビルドしないがインストールするファイル
#prefixオプションで指定したディレクトリ以下の/share/パッケージ名に配置
pkgdata_DATA=setting
#C言語からdesineとして参照
AM_CFLAGS= -DEVENTTABLE_CSV=""$(pkgdatadir)/setting""

#再帰的にmakeを実行
SUBDIRS= subdir subdir2/subsubdir 
EOF 
vim Makefile.am 
autoscan 
touch NEWS README AUTHORS ChangeLog 
awk '{if(/AC_INIT/){print "AC_INIT(FULL-PACKAGE-NAME, 0.0.1, name@hoge.jp)";print"AM_INIT_AUTOMAKE"}else{print $0}}' configure.scan >
congifure.ac 
vim configure.ac 
aclocal 
autoheader
autoconf
automake -a -c

C programming

Concepts to know
-Structs, arrays, pointers, and reference types
-File I/O
-Use of command line parameters
-Pass-by-reference and pass-by-value
-Dynamic memory allocation using malloc()
-Use of C libraries

Helpful Skills related C
-Debugging programs
-Reading documentation
-Iterative design
-Good coding standards

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>

struct test_struct
{
	int val;
	struct test_struct *next;
}

struct test_struct *head = NULL;
struct test_struct *curr = NULL;

struct test_struct* create_list(int val)
{
	printf("\n creating list with headnode as [%d]\n", val);
	struct test_struct *ptr = (struct test_struct*)malloc(sizeof(struct test_struct));
	if(NULL == ptr)
	{
		printf("\n Node creation failed \n");
		return NULL;
	}
	ptr->val = val;
	ptr->next = NULL;

	head = curr = ptr;
	return ptr;
}

struct test_struct* add_to_list(int val, bool add_to_end)
{
	if(NULL == head)
	{
		return (create_list(val));
	}

	if(add_to_end)
		printf("\n Adding node to end of list with value [%d]\n",val);
	else
		printf("\n Adding node to beginning of list with value [%d]\n", val);

	struct test_struct *ptr = (struct test_struct*)malloc(sizeof(struct test_struct));
	if(NULL == ptr)
	{
		printf("\n Node creation failed \n");
		return NULL;
	}
	ptr->val = val;
	ptr->next = NULL;

	if(add_to_end)
	{
		curr->next = ptr;
		curr = ptr;
	}
	else
	{
		ptr->next = head;
		head = ptr;
	}
	return ptr;
}

struct test_struct* search_in_list(int val, struct test_struct **prev)
{
	struct test_struct *ptr = head;
	struct test_struct *tmp = NULL;
	bool found = false;

	printf("\n Searching the list for value [%d] \n", val);

	while(ptr !=NULL)
	{
		if(ptr->val == val)
		{
			found = true;
			break;
		}
		else
		{
			tmp = ptr;
			ptr = ptr->next;
		}	
	}

	if(true == found)
	{
		if(prev)
			*prev = tmp;
		return ptr;
	}
	else
	{
		return NULL;
	}
}

int delete_from_list(int val)
{
	struct test_struct *prev = NULL;
	struct test_struct *del = NULL;

	printf("\n Deleting value [%d] from list\n",val);

	del = search_in_list(val,&prev);
	if(del == NULL)
	{
		return -1;
	}
	else
	{
		if(prev != NULL)
			prev->next = del->next;

		if(del == curr)
		{
			curr = prev;
		}
		else if(del == head)
		{
			head = del->next;
		}
	}
	free(del);
	del = NULL;

	return 0;
}	
void print_list(void)
{
	struct test_struct *ptr = head;

	printf("\n ----Printing list Start---- \n");
	while(ptr != NULL)
	{
		printf("\n [%d] \n",ptr->val);
		ptr = ptr->next;
	}
	printf("\n -------Printing list End ------ \n");
	return;
}

int main(void)
{
	int i = 0, ret = 0;
	struct test_struct *ptr = NULL;

	print_list();

	for(i = 5; i<10; i++)
			add_to_list(i,true);

	print_list();
	for(i =4; i>0; i--)
		add_to_list(i,false);

	print_list();

	for(i = 1; i<10; i += 4)
	{
		ptr = search_in_list(i, NULL);
		if(NULL == ptr)
		{
			printf("\n Search &#91;val = %d&#93; failed, no such element found\n",i);
		}
		else
		{
			printf("\n Search passed &#91;val = %d&#93;\n", ptr->val);
		}

		print_list();
		ret = delete_from_list(i);
		if(ret != 0)
		{
			printf("\n delete [val = %d] failed, no such element found\n",i);
		}
		else
		{
			printf("\n delete [val = %d] passed \n", i);
		}
		print_list();
	}
	return 0;
}

gcc

[vagrant@localhost c]$ gcc -v
Using built-in specs.
Target: x86_64-redhat-linux
コンフィグオプション: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
スレッドモデル: posix
gcc version 4.4.7 20120313 (Red Hat 4.4.7-17) (GCC)
#include <stdio.h>

int main(void){
  printf("hello world!\n");
  return 0;
}
[vagrant@localhost c]$ gcc -o hello hello.c
[vagrant@localhost c]$ ll
合計 12
-rwxrwxr-x. 1 vagrant vagrant 6425 11月 10 06:31 2016 hello
-rw-rw-r--. 1 vagrant vagrant   84 11月 10 06:30 2016 hello.c
[vagrant@localhost c]$ ./hello
hello world!

なお、Cでつまづきやすいと言われているポインタですが、アドレスの値を定義して(参照渡し)、データ型よりもメモリの消費を節約する仕組みで、より高速なプログラムが書けるようになります。

realloc()関数

割り当て済み猟奇のサイズを変更することができる。

#include 
#include 

#define BUFF_SIZE 256

int main(void)
{
    int i;
    unsigned char *pmem = NULL, *pmemsave = NULL, *pmemnew = NULL;
    
    pmemsave = pmem = (unsigned char *)malloc(BUFF_SIZE);
    if (pmem == NULL){
        fprintf(stderr, "メモリ割り当てに失敗しました。\n");
        exit(EXIT_FAILURE);
    }
    
    for (i = 0; i < BUFF_SIZE; i++)
        *pmem++ = (unsigned char)i;
    
    pmem = pmemsave;
    
    for (i = 0; i < BUFF_SIZE; i++)
        printf("%u ", *pmem++);
    printf("\n");
    
    pmemnew = realloc(pmemsave, BUFF_SIZE * 2);
    if (pmemnew != NULL){
        pmem = pmemnew;
        for (i = 0; i < BUFF_SIZE * 2; i++)
            printf("%u ", *pmem++);
        printf("\n");
        
        free(pmemnew); pmemnew = NULL;
    }
    else {
        free(pmemsave); pmemsave = NULL;
        
        fprintf(stderr, "メモリの再割り当てに失敗しました\n");
        exit(EXIT_FAILURE);
    }
    
    return 0;
}

bbi_misc.cpp

/*****************************/
/*filename:bbi_misc.cpp 雑関数*/
/*****************************/
#include "bbi.h"
#include "bbi_prot.h"

string dbl_to_s(double d)
{
    ostringstream ostr;
    ostr << d;
    return ostr.str();
}

string err_msg(const string& a, const string& b)
{
    if (a == "") return b + "が必要です。"
        if(b == "") return a + "が不正です。";
    return b + "が" + a + "の前に必要です。";
}

void err_exit(Tobj a, Tobj b, Tobj c, Tobj d)
{
    Tobj ob[5];
    ob[1] = a; ob[2] = b; ob[3] = c; ob[4]= d;
    cerr << "line:" << get_lineNo() << "ERROR";
    
    for (int i=1; i<=4 && ob[i].s! = "\1"; i++){
        if (ob[i].type == 'd') cout << ob[i].d;
        if (ob[i].type == 's') cout << ob[i].s;
    }
    cout << endl;
    exit(1);
}