[C言語] 文字列のコピー ポインタ変数の加算

自製str_copy関数のwhile文をポインタ変数の加算で書くと高速化できました。

以下のコードをそれぞれ走らせ処理時間を測ったところ、リストのインデックス加算に比べて1.5倍の速さになります。

strcpy関数はポインタ変数の加算になっているようです。

#include <stdio.h>

char *str_copy(char *d, const char *s)
{
	char *t = d;

	while (*d++ = *s++)
		;
	return t;
}

int main(void)
{
	char str[128] = "ABC";
	char tmp[128] = "DEF";

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

	str_copy(str, tmp);

	puts("コピーしました。");
	printf("str = \"%s\"\n", str);

	return 0;
}
#include <stdio.h>

char *str_copy(char *d, const char *s)
{
	int i=0;

	while (d[i] = s[i])
		i++;
	return d;
}

int main(void)
{
	char str[128] = "ABC";
	char tmp[128] = "DEF";

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

	str_copy(str, tmp);

	puts("コピーしました。");
	printf("str = \"%s\"\n", str);

	return 0;
}
import subprocess,time,datetime

start = time.time()

proc = subprocess.run("list1106_mac2", shell=True, stdout= subprocess.PIPE, stderr = subprocess.PIPE)
print(proc.stdout.decode('UTF-8'))

# 処理時間算出
process_time = time.time() - start
td = datetime.timedelta(seconds = process_time)
dt_now = datetime.datetime.now()

print('ポインタ加算 処理終了 ' + str(td) + ' ' + str(dt_now))

start2 = time.time()

proc = subprocess.run("list1106a_mac2", shell=True, stdout= subprocess.PIPE, stderr = subprocess.PIPE)
print(proc.stdout.decode('UTF-8'))

# 処理時間算出
process_time2 = time.time() - start2
td2 = datetime.timedelta(seconds = process_time2)
dt_now2 = datetime.datetime.now()

print('インデックス加算 処理終了 ' + str(td2) + ' ' + str(dt_now2))
--------------------------------------------------

出力
--------------------------------------------------
str = "ABC"
コピーしました。
str = "DEF"
ポインタ加算 処理終了 0:00:00.007981 2021-07-20 14:05:55.569973

str = "ABC"
コピーしました。
str = "DEF"
インデックス加算 処理終了 0:00:00.012111 2021-07-20 14:05:55.582141

[C言語] ポインタ渡し

ここまで学んだ段階で昨年読み進めていた新明解・入門編に再び目を通しました。

やはり10章 ポインタの説明が難解だったのと、最初の間違い例の解決法としてポインタ渡しを使っているところで戸惑いました。

Pythonユーザーからすれば、関数内で新たな変数が生成しているのに戻り値になっていない、戻り値に相当するはずの変数のポインタが引数になっている、あたりで混乱します。まあC言語が元祖ですからこちらが認識を改める他ないです。

この仕組みを利用すれば、関数の戻り値は引数にポインタ変数を入れることで何個でも設定できます。Pythonでは戻り値が複数の場合はタプルになっており、そこから各要素を取り出す手間がかかります。C言語にはそれがないのでかなり便利です。

教本の内容については、前にも書きましたがポインタの説明に男性名が値(身長)で女性名がポインタという例えを用いるのは分かりにくすぎていかがなものかと思います。

教本のコード例を私でも理解できるように書き改めました。sum_diff関数の第3引数と第4引数はアスタリスクをintに寄せてポインタ変数として表記する方が分かりやすいです。

ただアスタリスクが前に来ると2つ以上同じ行で宣言できなくなります。2つ目以降がint型になります。

int* a,b ではaはポインタ変数になるが、bは整数の変数になる。
int *a,*b が文法的には正しい。

理屈では前につけるべきだと思いますが、仕様上後ろに付ける方が実装する上でトラブルになりにくいです。

以前の記事で先に宣言した変数のアドレスがなぜ後ろの方なのか理由が分からないと書きました。それは後の変数を若い方に割り当てることでメモリからあふれるのを防ぐためではないかと考えています。本当のところを知りたいです。

#include <stdio.h>

void sum_diff(int n1, int n2, int* sum, int* diff)
{
	*sum  = n1 + n2;
	*diff = (n1 > n2) ? n1 - n2 : n2 - n1;
}

int main(void)
{
	int na, nb;
	int wa = 0, sa = 0;

	puts("二つの整数を入力してください。");
	printf("整数A:");   scanf("%d", &na);
	printf("整数B:");   scanf("%d", &nb);

	sum_diff(na, nb, &wa, &sa);

	printf("和は%dで差は%dです。\n", wa, sa);

	printf("naのアドレス %p\n",&na);
	printf("nbのアドレス %p\n",&nb);
	printf("waのアドレス %p\n",&wa);
	printf("saのアドレス %p\n",&sa);

	return 0;
}
--------------------------------------------------

出力
--------------------------------------------------
二つの整数を入力してください。
整数A:20
整数B:10
和は30で差は10です。
naのアドレス 0x7ffeecf685fc
nbのアドレス 0x7ffeecf685f8
waのアドレス 0x7ffeecf685f4
saのアドレス 0x7ffeecf685f0

[C言語] ポインタの概念 その3 Pythonとの比較

数値を代入した場合の2変数のポインタの状態をPythonと比較しました。

C言語ではポインタのアドレスは変わらずxとyで異なるまま、一方Pythonでは同じアドレスになりました。

これが何を意味するのか、手掛かりがあれば調べたいところです。

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

main()
{
int x = 1,y= 2;
int *ip;

    ip =&x;
    y = x;
 
    printf("xの値 %d\n",x);
    printf("yの値 %d\n",y);

    printf("xのアドレス %p\n",&x);
    printf("yのアドレス %p\n",&y);
    printf("*ipのアドレス %p\n",ip);
}
--------------------------------------------------

出力
--------------------------------------------------
xの値 1
yの値 1
xのアドレス 0x7ffeecb5967c
yのアドレス 0x7ffeecb59678
*ipのアドレス 0x7ffeecb5967c
>>> a=0
>>> b=3
>>> print(id(a))
140573474482448
>>> print(id(b))
140573474482544
>>> b=a
>>> print(id(b))
140573474482448
>>> print(id(a))
140573474482448

[C言語] ポインタの概念 その2 メモリ番地他 C89

前回の続きです。

xとyのアドレスが模式図の通りになっているか、以下のコードでそれぞれのアドレスを確認しました。

xのアドレスと*ipのアドレスは同じで図の正しいことが分かりました。yについてはポインタ変数はありませんが、4バイト若い番地が割り当てられています。

intのメモリ領域は4バイトなのでxとyは隙間なく並んでいます。気になることが一点。変数宣言はxが先なのになぜアドレスは後ろなのでしょう。*ipなしで宣言だけしても番地は変わらずでした。

#include <stdio.h>;

main()
{
int x = 1,y= 2;
int *ip;

    ip =&x;
    y = *ip;
    *ip = 0;

    printf("xのアドレス %p\n",&x);
    printf("yのアドレス %p\n",&y);
    printf("*ipのアドレス %p\n",ip);
}
--------------------------------------------------

出力
--------------------------------------------------
xのアドレス 0x7ffee4de267c
yのアドレス 0x7ffee4de2678
*ipのアドレス 0x7ffee4de267c

また、ISOのC90で禁止されているコード途中の変数宣言やC99から導入されたスラッシュ2つでのコメントアウトを試してみました。エラーにはなりませんでしたが、どちらにも警告がありました。

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

main()
{
int x = 1,y= 2;
int *ip;

    ip =&x;
    y = *ip;
    *ip = 0;

    printf("xのアドレス %p\n",&x);
    printf("yのアドレス %p\n",&y);
    printf("*ipのアドレス %p\n\n",ip);

int* ipy; // ポインタの宣言

    ipy = &y;

    printf("yのアドレス %p\n",&y);
    printf("*ipyのアドレス %p\n",ipy);

}
--------------------------------------------------

出力
--------------------------------------------------
<警告内容のみ>
warning: ISO C90 forbids mixing declarations and code

warning: // comments are not allowed in this language

[C言語] ポインタの概念

私が最近購入したC言語の教科書は丸暗記を強いる内容で何故?が記されていなかったため、だいぶ前に衝動買いしたK&R※を読んでいます。

ポインタの概念(P114)は下図の内容で私なりに理解しました。ポインタに辞書型様データを格納するという考え方です。矛盾が生じたら都度アップデートします。

※ プログラミング言語C 第2版 ANSI規格準拠(1989):B.W. カーニハン,D.M. リッチー著

[Python] exe化ツール v0.0.2 標準出力のデコード

前回の波カッコの問題は標準出力をデコードすることで解決しました。

実行前、distディレクトリ内に関連する旧ファイルがあれば手動で削除しておく必要があります(コードでは権限を変えても削除できませんでした)。

これでとりあえず完成でしょうか。

ただし、このコード自身をexe化してもうまく動作しないです。他のコードに対しては正常にexe化できます。カレントディレクトリを変更したりするのが良くないのかもしれません。

<関連箇所のみ>

def exe_make(path):
    # ソースコードの作業ディレクトリへのコピー
    working_dir = '/test_app/'
    new_path = working_dir + (path.split('test_GUI/'))[1]
    print(f'new_path {new_path}')
    shutil.copy2(path, new_path)

    # buildディレクトリ内関連ディレクトリの削除
    filename = (path.split('test_GUI/'))[1][:-3]
    remove_dir = '/test_app/build/' + filename + '/'
    try:
        shutil.rmtree(remove_dir)
    except:
        pass

    # 作業ディレクトリ内specファイルの削除
    all_files2 = [path for path in glob.glob('/test_app/*.spec')]
    remove_files2 = [path for path in all_files2 if filename in path]
    print(remove_files2)
    if len(remove_files2) != 0:
        for path in remove_files2:
            os.remove(path)

    # カレントディレクトリを作業ディレクトリへ変更
    os.chdir('/test_app/')

    # exeファイル作成コマンド実行
    def run(cmd):
        proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

        while True:
            line = proc.stdout.readline()
            if line:
                yield line
            if not line and proc.poll() is not None:
                break

    cmd = f"pyinstaller {new_path} --onefile --noconsole"
    lines = []
    for line in run(cmd):
        sys.stdout.buffer.write(line)
        lines.append(line.decode('utf-8'))
    lines_con = ''.join(lines)
    list_text()[0].insert(tk.END,'exeファイル作成完了\n')

    return lines_con

# Button設定
btn = ttk.Button(frame, text="実行",command=lambda:[list_text()[0].insert(tk.END,exe_make(entry.get())),auto_scroll()],width=8,style= 'MyWidget.TButton')
btn.grid(row=0,column=2,sticky=tk.W,padx=10)

[Python] exe化ツール v0.0.1 全標準出力の取得

pyinstallerを使ってソースコードから実行ファイルを作成するツールです。

標準出力を全て取得してTextウィジェットに表示するところで手間取りました。

標準出力を1行ずつ取得してリストにしたものをそのまま表示しているため、波カッコが目障りです。できれば消去したいです。

import subprocess,datetime,os,sys,shutil,glob
import tkinter as tk
import tkinter.font as font
from tkinter import ttk

# 16進数カラーコード
# #EDFFBE #C2EEFF #7B3CFF

class FrameA(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.configure(background = '#b0e0e6')
        self.grid(row=1,column=2, sticky=tk.NSEW, padx=5, pady=5)

class FrameB(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.configure(background = '#C2EEFF',borderwidth=0)
        self.grid(row=1,column=1, sticky=tk.NSEW, padx=5, pady=5)
        # Text設定
        self.text = tk.Text(self,height=23,width=45,highlightbackground="#f0f8ff",background = '#C2EEFF',foreground = '#8b0000')
        # ハイライトを消す場合
        # self.text = tk.Text(self,height=20,width=45,highlightthickness=0,background = '#C2EEFF',foreground = '#8b0000')

        # Y方向スクロールバーの設定
        self.scrollable_frame = ttk.Frame(self.text)
        self.scrollbar_y = ttk.Scrollbar(self, orient="vertical", command=self.text.yview,style= 'Vertical.TScrollbar')
        self.scrollbar_y.pack(side=tk.RIGHT, fill="y")

        self.text.configure(yscrollcommand=self.scrollbar_y.set)
        self.text.pack(side=tk.LEFT, fill="both", expand=True)

def list_text():
    # frameB全ウィジェットのinfoを取得
    children = frameB.winfo_children()
    text_list = [entry for entry in children if type(entry)==tk.Text]

    return text_list

def exe_make(path):
    # ソースコードの作業ディレクトリへのコピー
    working_dir = '/test_app/'
    new_path = working_dir + (path.split('test_GUI/'))[1]
    print(f'new_path {new_path}')
    shutil.copy2(path, new_path)

    # buildディレクトリ内関連ディレクトリの削除
    filename = (path.split('test_GUI/'))[1][:-3]
    remove_dir = '/test_app/build/' + filename + '/'
    try:
        shutil.rmtree(remove_dir)
    except:
        pass

    # 作業ディレクトリ内specファイルの削除
    all_files2 = [path for path in glob.glob('/test_app/*.spec')]
    remove_files2 = [path for path in all_files2 if filename in path]
    print(remove_files2)
    if len(remove_files2) != 0:
        for path in remove_files2:
            os.remove(path)

    # カレントディレクトリの変更
    os.chdir('/test_app/')

    # exeファイル作成コマンド実行
    def run(cmd):
        proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

        while True:
            line = proc.stdout.readline()
            if line:
                yield line
            if not line and proc.poll() is not None:
                break

    cmd = f"pyinstaller {new_path} --onefile --noconsole"
    lines = []
    for line in run(cmd):
        sys.stdout.buffer.write(line)
        lines.append(line)

    list_text()[0].insert(tk.END,'exeファイル作成完了\n')

    return lines


def list_text():
    # frameB全ウィジェットのinfoを取得
    children = frameB.winfo_children()
    text_list = [entry for entry in children if type(entry)==tk.Text]

    return text_list

def auto_scroll():
    list_text()[0].see("end")

# ウィンドウ作成
root = tk.Tk()
root.title("EXE MAKER v0.0.1")
root.geometry("555x375")
root.configure(bg='#b0e0e6')
style = ttk.Style()
style.theme_use('classic')
style.configure("MyWidget.TButton", gripcount=0,
                background="#7B3CFF", foreground="#EEFFFF",darkcolor='#7B3CFF', lightcolor="LightGreen",
                troughcolor="gray", bordercolor="gray", arrowcolor="white")
style.configure("MyWidget2.TButton", gripcount=0,
                background="#ffe4b5", foreground="#556b2f",darkcolor='#ffe4b5', lightcolor="LightGreen",
                troughcolor="gray", bordercolor="gray", arrowcolor="white")
style.configure("Vertical.TScrollbar", gripcount=0,
                background="#98fb98", foreground="#98fb98", darkcolor="#f5f5dc", lightcolor="#98fb98",
                troughcolor="#EEFFFF", bordercolor="#EEFFFF", arrowcolor="#EEFFFF")

# フォント設定
my_font = font.Font(root,family="System",size=18,weight="normal")
my_font2 = font.Font(root,family="System",size=16,weight="normal")
my_font3 = font.Font(root,family="System",size=14,weight="normal")
my_font4 = font.Font(root,family="System",size=12,weight="normal")

# Frame設定
frame = tk.Frame(root,background = '#b0e0e6')
frame.grid(row=0,column=0, sticky=tk.NSEW, padx=5, pady=10)
frameA = FrameA(master=frame)
frameB = FrameB(master=frame)

# Entry設定
entry = ttk.Entry(frame,width=45,background = '#C2EEFF',foreground = '#8b0000',font=my_font3)
entry.grid(row=0,column=1, padx=5,sticky=tk.W)

# Button設定
btn = ttk.Button(frame, text="実行",command=lambda:[list_text()[0].insert(tk.END,exe_make(entry.get())),auto_scroll()],width=8,style= 'MyWidget.TButton')
btn.grid(row=0,column=2,sticky=tk.W,padx=10)

btnA = ttk.Button(frameA, text="クリア",command=lambda:entry.delete(0,tk.END),width=8,style= 'MyWidget2.TButton')
btnA.pack(padx=5,pady=3,side=tk.TOP)

root.mainloop()

[Python] pyenv管理アプリ v0.0.6 コマンド直接入力

コマンド直接入力もできるようにしました。

<追記箇所のみ>

def direct(cmd):
    proc = subprocess.run(cmd, shell=True, stdout= subprocess.PIPE, stderr = subprocess.PIPE)
    return proc.stdout

btnG = ttk.Button(frameA, text="直接入力",command=lambda:[list_text()[0].insert(tk.END,direct(str(entry.get()))),auto_scroll()],width=8,style= 'MyWidget4.TButton')
btnG.pack(padx=5,pady=3,side=tk.TOP)

[Python] pyenv管理アプリ v0.0.5 pip関連操作

以下の4機能を追加しました。
1.pipによりインストールしたライブラリのリスト表示
2.アップデート可能なライブラリのリスト表示
3.ライブラリのアップデート
4.新規ライブラリのインストール

これでひと段落したのでexe化して普段使いします。

import subprocess,datetime,os
import tkinter as tk
import tkinter.font as font
from tkinter import ttk

# 16進数カラーコード
# #EDFFBE #C2EEFF #7B3CFF

class FrameA(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.configure(background = '#EDFFBE')
        self.grid(row=1,column=1, sticky=tk.NSEW, padx=5, pady=5)

class FrameB(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.configure(background = '#C2EEFF',borderwidth=0)
        self.grid(row=1,column=0, sticky=tk.NSEW, padx=5, pady=5)
        # Text設定
        self.text = tk.Text(self,height=20,width=45,highlightbackground="#f0f8ff",background = '#C2EEFF',foreground = '#8b0000')
        # ハイライトを消す場合
        # self.text = tk.Text(self,height=20,width=45,highlightthickness=0,background = '#C2EEFF',foreground = '#8b0000')

        # Y方向スクロールバーの設定
        self.scrollable_frame = ttk.Frame(self.text)
        self.scrollbar_y = ttk.Scrollbar(self, orient="vertical", command=self.text.yview,style= 'Vertical.TScrollbar')
        self.scrollbar_y.pack(side=tk.RIGHT, fill="y")

        self.text.configure(yscrollcommand=self.scrollbar_y.set)
        self.text.pack(side=tk.LEFT, fill="both", expand=True)

def version_check():
    proc = subprocess.run("pyenv versions", shell=True, stdout= subprocess.PIPE, stderr = subprocess.PIPE)
    return proc.stdout

def version_change(num):
    print(num)
    cmd = f"pyenv global {num}"
    subprocess.run(cmd, shell=True, stdout= subprocess.PIPE, stderr = subprocess.PIPE)
    proc = subprocess.run("pyenv versions", shell=True, stdout= subprocess.PIPE, stderr = subprocess.PIPE)
    return proc.stdout

def list_text():
    # frameB全ウィジェットのinfoを取得
    children = frameB.winfo_children()
    text_list = [entry for entry in children if type(entry)==tk.Text]

    return text_list

def auto_scroll():
    list_text()[0].see("end")

def piplist_check():
    proc = subprocess.run("python -m pip list", shell=True, stdout= subprocess.PIPE, stderr = subprocess.PIPE)
    return proc.stdout

def pipupd_check():
    proc = subprocess.run("python -m pip list --outdated", shell=True, stdout= subprocess.PIPE, stderr = subprocess.PIPE)
    return proc.stdout

def lib_update(lib):
    print(lib)
    cmd = f"python -m pip install -U {lib}"
    proc = subprocess.run(cmd, shell=True, stdout= subprocess.PIPE, stderr = subprocess.PIPE)
    return proc.stdout

def lib_install(lib):
    print(lib)
    cmd = f"python -m pip install {lib}"
    proc = subprocess.run(cmd, shell=True, stdout= subprocess.PIPE, stderr = subprocess.PIPE)
    return proc.stdout

# ウィンドウ作成
root = tk.Tk()
root.title("PYENV MANAGER v0.0.5")
root.geometry("480x330")
root.configure(bg='#EDFFBE')
style = ttk.Style()
style.theme_use('classic')
style.configure("MyWidget.TButton", gripcount=0,
                background="#7B3CFF", foreground="#EEFFFF",darkcolor='#7B3CFF', lightcolor="LightGreen",
                troughcolor="gray", bordercolor="gray", arrowcolor="white")
style.configure("MyWidget2.TButton", gripcount=0,
                background="#ffe4b5", foreground="#556b2f",darkcolor='#ffe4b5', lightcolor="LightGreen",
                troughcolor="gray", bordercolor="gray", arrowcolor="white")
style.configure("MyWidget3.TButton", gripcount=0,
                background="#2f4f4f", foreground="#EEFFFF",darkcolor='#2f4f4f', lightcolor="LightGreen",
                troughcolor="gray", bordercolor="gray", arrowcolor="white")
style.configure("MyWidget4.TButton", gripcount=0,
                background="#00008b", foreground="#EEFFFF",darkcolor='#00008b', lightcolor="LightGreen",
                troughcolor="gray", bordercolor="gray", arrowcolor="white")
style.configure("Vertical.TScrollbar", gripcount=0,
                background="#98fb98", foreground="#98fb98", darkcolor="#f5f5dc", lightcolor="#98fb98",
                troughcolor="#EEFFFF", bordercolor="#EEFFFF", arrowcolor="#EEFFFF")

# フォント設定
my_font = font.Font(root,family="System",size=18,weight="normal")
my_font2 = font.Font(root,family="System",size=16,weight="normal")
my_font3 = font.Font(root,family="System",size=14,weight="normal")
my_font4 = font.Font(root,family="System",size=12,weight="normal")

# Frame設定
frame = tk.Frame(root,background = '#EDFFBE')
frame.grid(row=0,column=0, sticky=tk.NSEW, padx=5, pady=10)
frameA = FrameA(master=frame)
frameB = FrameB(master=frame)

# Entry設定
entry = ttk.Entry(frame,width=25,background = '#C2EEFF',foreground = '#8b0000',font=my_font3)
entry.insert(tk.END, 'バージョン番号 or ライブラリ名') 
entry.grid(row=0,column=0, padx=5,sticky=tk.W)

# Button設定
btn = ttk.Button(frame, text="クリア",command=lambda:entry.delete(0,tk.END),width=8,style= 'MyWidget2.TButton')
btn.grid(row=0,column=1,sticky=tk.W,padx=10)

btnA = ttk.Button(frameA, text="Python確認",command=lambda:[list_text()[0].insert(tk.END,version_check()),auto_scroll()],width=8,style= 'MyWidget.TButton')
btnA.pack(padx=5,pady=3,side=tk.TOP)

btnB = ttk.Button(frameA, text="Python変更",command=lambda:[list_text()[0].insert(tk.END,version_change(str(entry.get()))),auto_scroll()],width=8,style= 'MyWidget.TButton')
btnB.pack(padx=5,pady=3,side=tk.TOP)

btnC = ttk.Button(frameA, text="pipLIST確認",command=lambda:[list_text()[0].insert(tk.END,piplist_check()),auto_scroll()],width=8,style= 'MyWidget3.TButton')
btnC.pack(padx=5,pady=3,side=tk.TOP)

btnD = ttk.Button(frameA, text="pipUPD確認",command=lambda:[list_text()[0].insert(tk.END,pipupd_check()),auto_scroll()],width=8,style= 'MyWidget3.TButton')
btnD.pack(padx=5,pady=3,side=tk.TOP)

btnE = ttk.Button(frameA, text="pipUPDATE",command=lambda:[list_text()[0].insert(tk.END,lib_update(str(entry.get()))),auto_scroll()],width=8,style= 'MyWidget3.TButton')
btnE.pack(padx=5,pady=3,side=tk.TOP)

btnF = ttk.Button(frameA, text="pipINSTALL",command=lambda:[list_text()[0].insert(tk.END,lib_install(str(entry.get()))),auto_scroll()],width=8,style= 'MyWidget4.TButton')
btnF.pack(padx=5,pady=3,side=tk.TOP)

root.mainloop()