ページ 1 / 1
c言語のポインタについて質問です。
Posted: 2011年5月26日(木) 14:26
by akatuki
この問題の解答を教えてください(できれば解説も)よろしくお願いします。
①文字列のポインタを引数とし、その文字列を最後の文字から初めまで逆順に表示する関数print_rev を作成せよ。
②2 個の文字列のポインタを引数として、それらを比較して、最初に異なる位置(0以上の整数)を返す関数str_diff_point を作成せよ。ただし、それらが、一致したときは-1 を返すこととする。
③2 個の文字列のポインタを引数とし、第2の文字列が第1のポインタの指す文字列に含まれているときは最初のポインタを返す関数strsearch を作成せよ。ただし、見つからないときはNULL を返すこととする。
Re: c言語のポインタについて質問です。
Posted: 2011年5月27日(金) 12:35
by ookami
①のみです!お役に立てば幸いです←
l;print_rev(char*s){s+=l=strlen(s);while(l--)putchar(*--s);}
Re: c言語のポインタについて質問です。
Posted: 2011年5月27日(金) 12:43
by バグ
じゃあ、私は③のみ・・・
コード:
char*strsearch(char*a,char*b){return strstr(a,b);}
Re: c言語のポインタについて質問です。
Posted: 2011年5月27日(金) 13:02
by jaken
一応ライブラリ等を使わない形で
コード:
// ①文字列のポインタを引数とし、その文字列を最後の文字から初めまで逆順に表示する関数print_rev を作成せよ。
void print_rev(char* str)
{
// 最終地点の検索
int i;
for(i = 0 ; i < 99 ; i++){
if(*(str+i) == '\0')break;
}
// 逆に表示
for(int n = i ; n >= 0 ; n--){
printf("%c", *(str+n));
}
printf("\n");
}
//②2 個の文字列のポインタを引数として、それらを比較して、最初に異なる位置(0以上の整数を返す
//関数str_diff_point を作成せよ。ただし、それらが、一致したときは-1 を返すこととする。
int str_diff_point(char* s1, char* s2)
{
int ret = 0;
for(;;){
if(*(s1+ret) == '\0' && *(s2+ret) == '\0')break;
if(*(s1+ret) == '\0' || *(s2+ret) == '\0')return ret;
if(*(s1+ret) == *(s2+ret))ret++;
else return ret;
}
return -1;
}
//③2 個の文字列のポインタを引数とし、第2の文字列が第1のポインタの指す文字列に含まれているときは最初のポインタを返す
//関数strsearch を作成せよ。ただし、見つからないときはNULL を返すこととする。
char* strsearch(char* s1, char* s2)
{
// s1の中にs2があるか検索
for(int i = 0 ; *(s1+i) != '\0' ; i++){
if(*(s1+i) == *(s2+0)){
int j;
for(j = 0 ; *(s1+i+j) == *(s2+j) ; j++){
if(*(s1+i+j) == '\0')return NULL;
}
if(*(s2+j) == '\0')return (s1+i);
}
}
return NULL;
}
Re: c言語のポインタについて質問です。
Posted: 2011年5月27日(金) 13:07
by bitter_fox
①です、若干使いにくいです。
コード:
print_rev(char*s){for(s+=strlen(s);*--s;putchar(*s));}
ポインタを文字列の末尾まで進めてそこからヌル文字が出てくるまで一文字ずつ出力します。
コード:
// 確保及び呼び出し。
main()
{
char *s = (char*)calloc(257, sizeof(char))+1;
scanf("%255s", s);
print_rev(s);
}
Re: c言語のポインタについて質問です。
Posted: 2011年5月27日(金) 14:54
by かずま
bitter_fox さんが書きました:
コード:
print_rev(char*s){for(s+=strlen(s);*--s;putchar(*s));}
ポインタを文字列の末尾まで進めてそこからヌル文字が出てくるまで一文字ずつ出力します。
先頭文字のひとつ前を参照してはいけませんし、そこに '\0' があるとも限りません。
コード:
print_rev(char*s){*s?print_rev(s+1),putchar(*s):0;}
これだと、グローバル変数も strlen() も使いません。
Re: c言語のポインタについて質問です。
Posted: 2011年5月27日(金) 15:02
by かずま
かずま さんが書きました:先頭文字のひとつ前を参照してはいけませんし、そこに '\0' があるとも限りません。
よく見ていなくて、すみませんでした。calloc で余分に領域を確保しているんですね。
Re: c言語のポインタについて質問です。
Posted: 2011年5月27日(金) 17:21
by maru
かずま さんが書きました:かずま さんが書きました:先頭文字のひとつ前を参照してはいけませんし、そこに '\0' があるとも限りません。
よく見ていなくて、すみませんでした。calloc で余分に領域を確保しているんですね。
正しいご指摘だと思いますよ。関数の仕様にはそんな前提条件は書かれていませんからね。
いくら使用例でcalloc で余分に領域を確保していても、仕様は満足しません。
かずま さんが書きました:bitter_fox さんが書きました:
コード:
print_rev(char*s){*s?print_rev(s+1),putchar(*s):0;}
これだと、グローバル変数も strlen() も使いません。
print_rev関数の型はintでしょうか?省略せずに書いた方がよいと思います。
Re: c言語のポインタについて質問です。
Posted: 2011年5月27日(金) 17:41
by ookami
l;print_rev(char*s){s+=l=strlen(s);while(l--)putchar(*--s);} // ookami 60byte
print_rev(char*s){for(s+=strlen(s);*--s;putchar(*s));} // bitter_foxさん 54byte (難あり)
print_rev(char*s){*s?print_rev(s+1),putchar(*s):0;} // かずまさん 51byte
今のところ、かずまさんのコードが一番短いですね!
再帰や三項演算子をフツーに使ってきてるあたり、手馴れた感が...w
Re: c言語のポインタについて質問です。
Posted: 2011年5月27日(金) 21:02
by maru
ookami さんが書きました:l;print_rev(char*s){s+=l=strlen(s);while(l--)putchar(*--s);} // ookami 60byte
print_rev(char*s){for(s+=strlen(s);*--s;putchar(*s));} // bitter_foxさん 54byte (難あり)
print_rev(char*s){*s?print_rev(s+1),putchar(*s):0;} // かずまさん 51byte
今のところ、かずまさんのコードが一番短いですね!
再帰や三項演算子をフツーに使ってきてるあたり、手馴れた感が...w
短けりゃいいってもんではないでしょう。可読性のほうが重要です。
その点ではookamiさんのコードのほうが好ましいと考えます。(変数 l が関数ローカルでないのがいただけませんが。)
文字列処理で1文字につき1回再帰呼び出しを使うのはどうなんでしょうか。再帰構造は確かにスマートですが、コストがかかります。そのことをわかって使うのならばいいでしょうが、知らずに使うと痛い目にあいます。
Re: c言語のポインタについて質問です。
Posted: 2011年5月28日(土) 02:23
by ISLe
難読コードは丸投げ連投をこらしめるためじゃないんですかね。
#この投稿も無粋だと思いましたが。
Re: c言語のポインタについて質問です。
Posted: 2011年5月28日(土) 15:59
by maru
ISLe さんが書きました:難読コードは丸投げ連投をこらしめるためじゃないんですかね。
私もそんなところだろうと思っているんですが、そのコードがいかにも優れているかのようなコメントには賛成いたしかねます。初心者がこれを見てこんなコードがいいんだと思われても困りますからね。
Re: c言語のポインタについて質問です。
Posted: 2011年5月29日(日) 12:11
by たいちう
> その点ではookamiさんのコードのほうが好ましいと考えます。
maruさんはookamiさんのコードの可読性が良いとお考えなのですね。
初心者がこれを見てこんなコードがいいんだと思っても構わないと。
Re: c言語のポインタについて質問です。
Posted: 2011年5月29日(日) 17:14
by かずま
No.4 の jaken さんのプログラムについては誰も何も言わないのでしょうか?
(1) なぜか文字数に 99 の制限がある。
逆順文字列の前後に勝手に '\0' と '\n' をつける。
(2) とりあえず仕様どおりには動きそうですが、無駄が多い。
(3) strsearch("abc", "bc") が NULL を返す。
真面目に書けばこんなところでしょうか。
コード:
void print_rev(const char *s)
{
int i = 0;
while (s[i] != '\0') i++;
while (--i >= 0) putchar(s[i]);
}
int str_diff_point(const char *s1, const char *s2)
{
int i;
for (i = 0; s1[i] == s2[i]; i++)
if (s1[i] == '\0') return -1;
return i;
}
char *strsearch(const char *s1, const char*s2)
{
do {
const char *p1 = s1, *p2 = s2;
do {
if (*p2 == '\0') return (char *)s1;
} while (*p1++ == *p2++);
} while (*s1++);
return NULL;
}
Re: c言語のポインタについて質問です。
Posted: 2011年5月29日(日) 17:28
by かずま
かずま さんが書きました:
コード:
while (--i >= 0) putchar(s[i]);
これはバグです。次のように訂正します。
コード:
while (i-- > 0) putchar(s[i]);
Re: c言語のポインタについて質問です。
Posted: 2011年5月29日(日) 23:06
by かずま
かずま さんが書きました:これはバグです。次のように訂正します。
すみません。これ、勘違いです。
unsigned int i; だったら、前者はバグですが、int i; なので、どちらでもかまいません。
int i; の代わりにポインタを使った場合は、そのポインタが元の文字列の先頭より
前を指してはいけませんから、while の中にデクリメントを書くことはできません。
コード:
void print_rev(const char *s)
{
const char *p = s;
while (*p != '\0') p++;
while (p > s) putchar(*--p);
}
Re: c言語のポインタについて質問です。
Posted: 2011年5月30日(月) 11:25
by ookami
どうもすいません、ookamiです。
コードゴルフを演出して余計な刺激を生んでしまい、申し訳ないです。
「こらしめる」というほど立派なことは考えていませんでしたが、
フォーラムルールにも「丸投げはNG」とあるので、
「直球で模範解答を返しちゃいけないだろうなぁ」くらいには思っていました。
それで、思いつき的にコードゴルフを始めてしまいました。すいません。
「可読性の方が重要」かどうかは、場合によりけりかと思いますし、
もちろん、最初に私が投稿したコードも「読みやすい」とは思っていません。
バグさん・bitter_foxさん・jakenさん・かずまさんのコードについても、特に批評を書くつもりはないです。
質問者のakatukiさんからの返事がまだですが、
丸投げが公然と認められている掲示板もありますから、
もうそちらで解決しているかもしれませんし、
私は、このトピックは「この辺でおひらき」でもいいかなぁと思っています。
ただ、「真面目に書くなら」といった流れもありますので、
そこは続けてもいいかもしれませんね?