11_高度なプログラミング.md
ポインタを返す関数
- 実用的なプログラムではポインタを返す関数が使用される。
サンプルコード
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
char *mystrcat(char *str1, char *str2);
int _tmain(int argc, _TCHAR* argv[])
{
char str1[16] = "abc";
char str2[16] = "def";
printf("%s\n", mystrcat(str1, str2));
return 0;
}
char *mystrcat(char *str1, char *str2){
char *ptr;
int n = 0;
ptr = str1 + strlen(str1);
while (*(ptr + n) = *(str2 + n)){
n++;
}
return str1;
}
出力結果
abcdef
str1 + strlen(str1) = '\0'
- while条件が偽となるのは
*(ptr + n)
に'\0'
が代入された時 =>*(str2 + n) == '\0'
の時- それまでは、
ptr
にstr2の値を一文字ずつ格納していく。
- それまでは、
サンプルコード2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* mystrcat(char* str1, char* str2);
int main(){
char str1[32] = "Hello, ";
char str2[16] = "World!\n";
printf(mystrcat(str1, str2));
return 0;
}
char *mystrcat(char* str1, char* str2){
char *aorg;
aorg = str1;
while (*str1){
str1++;
}
while (*str1++ = *str2++);
return aorg;
}
出力結果
Hello, World!
- 先に、str1の開始位置を保存しておく
aorg = str1;
-
str1
のポインタが\0
を指すまで(str1の最後まで)ポインタを進める。while (*str1){ str1++; }
str1
の後ろに、str2
を格納する。str2
が'\0'
になったらループを抜ける。
関数へのポインタ
- DLL中の関数を呼び出す際に使用する。
関数のアドレス
- 下記のようにして参照することが可能
pritf("main関数のアドレス = %p\n",main);
pritf("func関数のアドレス = %p\n",func);
関数へのポインタ
- 下記のように宣言することが可能
int (*ptr)(); //intは戻り値の型
サンプルコード
#include <stdio.h>
int main(){
int myFunc(char*,char*);//プロトタイプ宣言
int(*ptr)(char*, char*); // 関数へのポインタ
ptr = myFunc;
(*myFunc)("田中", "学生");
(*ptr)("小西", "会社員");
myFunc("佐藤", "自衛官");
return 0;
}
int myFunc(char *str1, char *str2){
printf("%sさんは、%sです。\n", str1, str2);
return 0;
}
出力結果
田中さんは、学生です。
小西さんは、会社員です。
佐藤さんは、自衛官です。
関数のポインタの配列
- 関数のポインタの配列を作成することも可能である。
サンプルプログラム
#include <stdio.h>
#include <stdlib.h>
#include "Calcarea.h"
int main(){
double(*func[3])() = { triangle, trapezoid, circle };
char ret[8];
int funcNo;
while (1){
printf("Which figure you want calcrate area?\n"
"1: triangle 2: trapezoid 3: circle 4: exit\n");
gets_s(ret);
if (ret[0]<'0' || ret[0] > '3'){
printf("番号が不正です。\n");
continue;
}
ret[1] = '\0';
funcNo = atoi(ret);
if (funcNo == 0){
break;
}
double area = func[funcNo - 1]();
printf("面積は%fです。\n", area);
}
return 0;
}
- 具体的なメソッドは省略(本筋ではないので…)
出力結果
Which figure you want calcrate area?
1: triangle 2: trapezoid 3: circle 4: exit
1
Calculate the area of ??the triangle.
input Base value ... 10
input height value ... 2
面積は10.000000です。
Which figure you want calcrate area?
1: triangle 2: trapezoid 3: circle 4: exit
2
Calculate the area of ??the trapezoid.
input upperBase value ... 5
input bottom value ... 2
input height value ... 8
面積は28.000000です。
Which figure you want calcrate area?
1: triangle 2: trapezoid 3: circle 4: exit
0
- 関数のポインタ配列の宣言:
double(*func[3])() = { triangle, trapezoid, circle };
- 関数のポインタ配列の使用
double area = func[funcNo - 1]();
可変個の引数を持つ関数の作成
stdarg.h
をincludeする。- 関数の形は
int func(int arg, ...);
- 関数内で
va_list型変数(ポインタ)
を宣言する。 va_start(3.で宣言したポインタ、オプション引数の型);
、va_end(3.で宣言したポインタ)
という2つのマクロで挟まれた部分で、オプション引数を取得する。- 最初のオプション引数は「
va_arg(3.で宣言したポインタ,オプション引数の型);
」というマクロで取得する。- va_argマクロをもう一度呼び出すと次のオプション引数を受け取ることが可能。
サンプルコード
#include <stdio.h>
#include <stdarg.h>
int myfunc(int a, ...);
int main(){
int wa;
wa = myfunc(4, 1, 2, 3, 4);
printf("wa = %d\n", wa);
wa = myfunc(2, 100, -45);
printf("wa = %d\n", wa);
return 0;
}
int myfunc(int x, ...){
va_list ptr;
int i, sum = 0;
va_start(ptr, x);
for (i = 0; i < x; i++){
sum += va_arg(ptr, int);
}
va_end(ptr);
return sum;
}
出力結果
wa = 10
wa = 55
サンプルコード2
- 例1だと、わざわざ第一引数に引数の数を明示しなければならないので、
最後の引数に
NULL
を渡すという方法もある。
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
char* myfunc(char*, ...);
int main(){
char str1[256] = "Today is "; /*十分な余白を確保しておく*/
char *str2 = "sunny, but";
char *str3 = "I don't know what the weather is tommorow\n";
myfunc(str1, str2, str3,"");
printf(str1);
return 0;
}
char* myfunc(char* p, ...){
va_list ptr;
char *str;
if (p[0] == '\0'){
return p;
}
va_start(ptr, p);
while (1){
str = va_arg(ptr, char *);
if (str[0] == '\0'){
break;
}
strcat_s(p, 256,str);
}
va_end(ptr);
return p;
}
出力結果
Today is sunny, butI don't know what the weather is tommorow