c言語でポインタ変数を用いた配列の反転操作を行いたいのですが、文字列の反転の仕方が分かりません。流れとしては、文字列の長さを調べてから文字列を反転して表示するという感じです。どうか教えてください。また、その他問題点があればご指摘よろしくお願いします。

#include <stdio.h>

int strlength(char *str) { /* 文字列の長さを調べる /*
int length = 0;

while (*str++ != '\0'){
length++;
}
return length;
}

int main(void) { /*配列strSrc[]の文字列を逆にして配列strDst[]に格納する */
char strSrc[] = "reverse this";
char *pC;
char strDst[] = "01234567890123456789";
char *pD;
int length;

printf( "%s\n", strSrc );

/* この部分が分かりません */

printf("%s\n", strDst ) ;

return( 0 );
}

このQ&Aに関連する最新のQ&A

A 回答 (15件中1~10件)

質問者さんの意図を素直に読み取ると、こんなのでもいいかも。



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

int main(void)
{
char s[] = "reverse this", *p, *q, t;

printf("逆転前:%s\n", s);
for (p = s, q = &s[strlen(s)-1]; p < q; p++, q--) {
t = *p, *p = *q, *q = t;
}
printf("逆転後:%s\n", s);
return 0;
}
    • good
    • 0

>流れとしては、文字列の長さを調べてから文字列を反転して表示するという感じです。



>/*配列strSrc[]の文字列を逆にして配列strDst[]に格納する */

 質問者様の「望む結果」は、No.2 さんのような結果の他に、

 "siht esrever23456789" とも考えられます(特にソースから)。

 これを実現するソースを回答します。

( No.2 さんのような結果を望むのであれば、格納後、出力直前に strDst[ iLength + 1 ] = '\0'; )

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

int main( void )
{
 char strSrc[] = "reverse this";
 char strDst[] = "01234567890123456789";
 char *pS = strSrc;
 char *pD = strDst;
 int iLength;

 iLength = strlen( strSrc ) - 1; // - 1 に注意

 printf( "%s\n", strSrc );

 pD += iLength; // 長さ分、後方へ

 while( *pS ){

  *pD = *pS; // 1文字ずつ「格納する」

  pS++; // 後方へ
  pD--; // 前方へ
 }
 printf( "%s\n", strDst );

 return( 0 );
}
注:インデントに全角空白を用いています。コピペ後、タブに一括変換して下さい。
    • good
    • 0

>#12さん


そりゃそうですね。これは一本取られました。:D
    • good
    • 0

>#10, 11


それをやるならいっそ「文字列の最後から先頭に向けて1文字ずつ画面表示」してしまえば入れ替えルーチンすら不要ですが。
    • good
    • 1

>・先頭と最後を入れ替える



言わずもがなですが、ここでいう「最後」とは'\0'のことではないです。
    • good
    • 0

対象配列の


・先頭と最後を入れ替える
・先頭の次と最後の前を入れ替える
・…
を適切に繰り返せば、strDst[]は不要で、十分な領域が必要云々の議論も不要ですね。
    • good
    • 0

受け手になる strDst に十分な領域を確保しなきゃいけないのは #8 の通りで, 正攻法で行くなら malloc で動的に確保するんだけど手を抜くなら (今の場合は)


char strDst[sizeof strSrc];
でも OK.
あと, 本当は「文字列を反転する」という関数を作った方がいいような気がする. インターフェースは string.h の strcpy/strncpy とか (標準にはないけど) strdup に合わせる方向で.
    • good
    • 0

逆順コピーの手順自体は既に書かれています(※)が、元コードはもともとstrSrcがstrDstより長いとエラーになる、という問題を抱えています。


※敢えて言うなら#7の手順はどこかでstrDstの終端を入れる必要がある、というくらい

汎用性を上げるならstrDstは動的に確保する方がいいです。
char *strDst;
strDst = malloc(sizeof(char) * (length + 1));

length + 1で確保するのはlengthに渡る値が終端文字分を含まないためです。
    • good
    • 0

#6さんへ



>2) 文字列の先頭アドレスを ポインタpCに代入
>3) 文字列の末尾アドレスを ポインタpDに代入
>3) ループで末尾側と先頭側を入れ替え

これだと、「配列strSrc[]の文字列自体を逆にする」という仕様になります。しかし、元の質問では「配列strSrc[]の文字列を逆にして配列strDst[]に格納する」という仕様なので、違ったものになってしまいますね。
strSrcの内容を逆にしてからstrDstにコピーするのなら結果は一緒ですが、おそらく出題の意図からは外れてしまうと思います。
なのでここは、下記のような流れになるかと。

2) strSrcの先頭アドレスを ポインタpCに代入
3) strDstの末尾アドレスを ポインタpDに代入
4) 文字列の長さ分、下記を繰り返す
4-1) pC→pDに値を代入
4-2) pCをインクリメント
4-3) pDをデクリメント
    • good
    • 0

考え方は


1) 元の文字列の長さを取得
2) 文字列の先頭アドレスを ポインタpCに代入
3) 文字列の末尾アドレスを ポインタpDに代入
3) ループで末尾側と先頭側を入れ替え
  pCをインクリメント ... 末尾側へ移動
  pDをデクリメント ... 先頭側へ移動
4) pCとpDを比較して交差するかまたは同一ならループ終了
  要素が偶数なら ... 交差
  要素が奇数なら ... 同一
といった具合でしょう

4)の判定ですが
01234567890123456789 この文字列を処理していくと
98765432190876543210 10回目のループで 10文字目の『9』と11文字目『0』の入れ替えをします
これで98765432109876543210が逆順になり完成します
このとき pCとpDは
pC = &strDst[9], pD = &strDst[10] です
ループでpC++ pD-- を実行すると
pC = &strDst[10], pD = &strDst[9] になり交差します

奇数だった場合は pC = &strDst[9], pD = &strDst[9] のように中心の文字を指すときがありますのでこれを終了条件にします

このようにして終了判定をしないと せっかく逆順にした文字列を
もう一度逆順に加工してしまい 結果として逆順の逆順つまり元通りにしてしまうことがあります
    • good
    • 0

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Qポインタのポインタの初期化法

 文字列をポインタを使って扱うとき、例えば、初期化は次のように行えますよね。

#include <stdlib.h>
char *s;
s = (char *)malloc(1000);
(これに続いてscanf("%s", s);など)

 これと同様にして、二次元の配列を、ポインタのポインタを使って表したいとき、

char **s;

と宣言したものを、malloc()関数を使って初期化することはできるのでしょうか。よろしくお願いします。

Aベストアンサー

mallocで2次元配列を確保するためには
まず各行の先頭アドレスを確保してから、各行の先頭アドレスに各列を確保するようにします。
具体的には10行20列を確保したい場合

int c = 10, r = 20;
char **s;
s = (char**)malloc(c*sizeof(char*));
for(i=0; i<c; i++){
  s[i] = (char*)malloc(r*sizeof(char));
}

と確保します。

注意としてはメモリの解放のfreeは、メモリを確保した各場所で行わないと適正に解放されないので
for(i=0; i<c; i++){
  free(s[i]);
}
free(s);

とします。

Qchar *str; と char* str;

char *str; と char* str;
どっちも同じことを意味しているんですか?

Aベストアンサー

同じことを指している、というのは、先の回答の通りです。

また、ひとつの宣言で変数を複数宣言したときに、char* str という表記は間違い
易いじゃないか、ということが言われているのも事実です。実際、いろいろな C のソースを
見ていても、まずアスタリスクを型につけて書くのは、まずお目にかかれません。

ただ C++ では、char* str という宣言も良く使われています。

C++ に限らずオブジェクト指向の言語は、強く型を意識するので、「文字のポインタ型」と
いう意味で、まとめて書く方が馴染むのでしょう。ちなみにそういう風な人たちは

char *str1, *str2;

とは、書けない体になっています。

char* str1;
char* str2;


変数の宣言だと、C に慣れていれば、char* str というのはちょっと違和感があるのは
私も分かりますが、関数のプロトタイプ宣言だと、どちらの方がすっきりしますか?

extern char *memcpy(char *, const char *);

extern char* memcpy(char*, const char*);


# まあ、どっちが正しい、っていうんじゃ無いんですよね

同じことを指している、というのは、先の回答の通りです。

また、ひとつの宣言で変数を複数宣言したときに、char* str という表記は間違い
易いじゃないか、ということが言われているのも事実です。実際、いろいろな C のソースを
見ていても、まずアスタリスクを型につけて書くのは、まずお目にかかれません。

ただ C++ では、char* str という宣言も良く使われています。

C++ に限らずオブジェクト指向の言語は、強く型を意識するので、「文字のポインタ型」と
いう意味で、まとめて書く方が馴染む...続きを読む

Q構造体の初期化の時にポインタを入れるにはどうしたらいいですか?

構造体の初期化の時にポインタを入れるにはどうしたらいいですか?

例えば、このような構造体で↓
struct PACKET {
uint16_t size; // データの長さ
uint16_t *data; // データバイト列
};

初期化の時にsizeとdataを入れるにはどうしたらいいのでしょうか?
dataがuint16_t*じゃなくてchar*なら

struct PACKET {
uint16_t size; // データの長さ
char *data; // データバイト列
};
struct PACKET p = { 5, "12345" };

というようにできるのですが・・・

Aベストアンサー

起動時にデータの入ったポインタを指定したいなら別に配列で用意した変数を代入するしかなさそうですが
static uint16_t init_data[] = {1,2,3,4,5};
struct PACKET p = { 5, init_data };

Qvoid (*signal(int signum, void (*handler)(int)))(int);

の解釈を教えてください
最後の「(int)」については詳しくお願いします

Aベストアンサー

signalが

(1)1つ目の引数の型:int
(2)2つ目の引数の型:引数がintで戻り値がvoidである関数へのポインタ
(3)戻り値の型:引数がintで戻り値がvoidである関数へのポインタ(2と同じ)

を満たす関数である事を宣言しています。最後の(int)はsignalの戻り値の
関数ポインタがint型の引数を持つ事を示しています。

「引数がintで戻り値がvoidである関数へのポインタ」の型をHANDLERと表すと

HANDLER signal(int signum, HANDLER handler);

となります。

Q関数へのポインタ渡しでの配列の初期化について

はじめまして、C言語の基本的な質問をさせてください。

C言語で、外部関数へポインタで引数を渡す場合に、
関数に渡されるのはアドレスですよね?

で、渡された関数側でそのポインタの配列の初期化を
するときにはアドレスだけの情報だと、要素数がいくつ
あるか分からず、領域の破壊をしてしまいそうな気が
するのですが?いかがでしょうか?

また、関数かなんかで、配列の要素数が分かる関数が
あったような気がするのですが、それもアドレスだけ
でわかるのでしょうか?

Aベストアンサー

疑問に思っていらっしゃる通りです。

渡された関数側では、要素数がいくつあるかわかりません。
初期化をするならば、ポインタと一緒に、要素数の情報も渡してやる必要があります。

配列の要素数がわかる関数はありません。
マクロ(プリプロセッサ)で、配列要素数を計算するのは可能ですが、
これは使用場所が限定されています。
配列を宣言したすぐ近くでないと役に立ちません。
渡された関数側では使えません。

C言語では、配列はその要素数とともに扱う必要があり、
そこをうっかりするとバグが発生する危険があります。

Qchar型+char型ってint型? if(char型==int型)?

C言語の「汎整数拡張(インテグラルプロモーション)」というものに関するものだと思います。

char型とchar型を加えた結果は、char型でしょうか。それともint型でしょうか。
(下のプログラムの
printf("sizeof(a[0]+a[1])は%d\n", sizeof(a[0]+a[1])); /* char型+char型 */
という部分の結果は4なので、int型と考えるべきなのかな。)

私は、char型とint型の加算の結果はint型だと思っていましたが、
char型とchar型の加算の結果はやはりchar型だと思っていました。
(それが間違えているのでしょうか。)


if(a[0]==i) /* char型とint型の比較(?) */
の部分では、左辺はchar型、右辺はint型ですが、このように型の違う変数を比較しても文法上構わないのでしょうか。
(私は、「比較は必ず型の同じもの同士でしかできない」と思っていました。)
左辺はchar型のように見えて、じつはint型ですか。


#include <stdio.h>
int main(void)
{
char a[4];
int i=77;
printf("sizeof(int)は%d\n", sizeof(int));
printf("sizeof(char)は%d\n", sizeof(char));
printf("sizeof('M')は%d\n", sizeof('M'));
printf("sizeof(a[0])は%d\n", sizeof(a[0]));

a[0]='M';
a[1]=7+6;
a[2]=a[0]+a[1];
printf("sizeof(a[0]+a[1])は%d\n", sizeof(a[0]+a[1])); /* char型+char型 */
printf("sizeof(+a[0])=%d\n", sizeof(+a[0]));

if(a[0]==i) /* char型とint型の比較(?) */
puts("a[0]==i");
else
puts("a[0]!=i");

return(0);
}

ちなみにワーニングもエラーもなんにもでません。

C言語の「汎整数拡張(インテグラルプロモーション)」というものに関するものだと思います。

char型とchar型を加えた結果は、char型でしょうか。それともint型でしょうか。
(下のプログラムの
printf("sizeof(a[0]+a[1])は%d\n", sizeof(a[0]+a[1])); /* char型+char型 */
という部分の結果は4なので、int型と考えるべきなのかな。)

私は、char型とint型の加算の結果はint型だと思っていましたが、
char型とchar型の加算の結果はやはりchar型だと思っていました。
(それが間違えているのでしょう...続きを読む

Aベストアンサー

「sizeof 単項式」について補足です。

これは sizeof 演算子が「単項演算子」であるために書かれたものだと思われます。
例えば同様に単項演算子である ++ も、「++ 単項式」です。

では単項式とは何なのかというと、これは以下のようなものを指します。(抜けがあるかもしれませんが。)
・定数
・名前(変数名や関数名など)
・( 式 )
・後置式

( 式 ) はおなじみの「式の結果を返す」ものですが、実はこれ全体で単項式です。
本来「sizeof 単項式」では ( ) を必要としないので、sizeof より優先順位の低い演算子を含む式を裸で渡すことはませんが、( ) で囲めばどんな式でも書けるわけです。

後置式は「配列構文によるアドレス参照式」や「関数呼び出し式」、「メンバ参照式」「後置型インクリメント/デクリメント式」です。
なので、
> sizeof(a[0])
> と書いたら、[ ] という演算子は2項演算子だから、a[0]は単項式になっていない
は、わざわざ ( ) で囲まず sizeof a[0] と書いても、正しい単項式なので問題ありません。
(これらの演算子は、全て sizeof より優先順位が上になっています。)

先に ++ も単項式を取る、ということを書きましたが、++ だって
  ++*(p + n)
のような記述が通るのだから、sizeof でも問題がなくて当然です。

また、例えば ++ では「オペランドは左辺値でなければならない」という原則があり、左辺値でない式に ++ を適用するとコンパイルエラーが発生します。
しかし、sizeof に「オペランドはオブジェクトでなければならない」などという原則を聞いたことがありません。
無論コンパイルエラーも起きませんし、期待通りに式の値のサイズが返ります。
「式の値のサイズ」というのはコンパイル時に判明しているものなので、取得できて当然といえば当然ですが、これがCで定められた仕様かどうかというのは残念ながら見つけることはできませんでした。
ただし、質問にあるような sizeof の文法は全て正しく、警告が出ないのは仕様通りだというのは間違いありません。

「sizeof 単項式」について補足です。

これは sizeof 演算子が「単項演算子」であるために書かれたものだと思われます。
例えば同様に単項演算子である ++ も、「++ 単項式」です。

では単項式とは何なのかというと、これは以下のようなものを指します。(抜けがあるかもしれませんが。)
・定数
・名前(変数名や関数名など)
・( 式 )
・後置式

( 式 ) はおなじみの「式の結果を返す」ものですが、実はこれ全体で単項式です。
本来「sizeof 単項式」では ( ) を必要としないので、sizeof より優...続きを読む

QC++のクラスポインタの初期化?

C言語しか経験がないものです。最近Irrlichtでゲームをつくりはじめました。いきなりチュートリアルがわからないので質問させていただきます。

IrrlichtDevice *device =
createDevice( video::EDT_SOFTWARE, dimension2d<u32>(640, 480), 16,
    false, false, false, 0);

if (!device)
return 1;

という部分で、
(1) *devide = createDevice( ...);
 なぜクラスポインタが関数で初期化できるのですか。
 アドレスを入れないのはなぜなのでしょうか。

(2) if(!device)
 これだとアドレス値の式を判別しているように思いますが、どういうことですか。

初歩的な質問で申し訳ございません。

Aベストアンサー

若干語弊があるのですが。
C++のクラス、というのは、Cの構造体を拡張したものと考えてください。

> (1) *devide = createDevice( ...);

createDeviceの宣言を見てないのですが、IrrlichtDevice へのポインタを返す関数になってませんか?
Cでも
struct A * foo(~)
とかいう風に構造体(struct A)へのポインタを返す関数ってありますよね?

> (2) if(!device)
ポインタは NULL なら 「偽」、そうでないなら「真」です。
!は論理値の真偽を反転させます。
これはCでもよく使われる記法です。

例)
FILE *fp = fopen(~);
if (!fp){ /* → fp == NULL と同義 */
エラー;
}

> device だけならアドレスで、*device だとさしているオブジェクトそのものをあらわすと入門書には書いてある

それは「IrrlichtDevice クラスへのポインタ」と宣言されているからです。
宣言(+初期化)と、それ以外での使い方が違うのはCも同じです。

struct A * a; は struct Aへのポインタ aの宣言
それ以降のプログラム中では
a は struct Aへのポインタ
*a は aの実体(=strcut Aそのもの)

struct A b; では struct Aの変数 bの宣言
それ以降のプログラム中では
b は struct A型の実体
*b は bがポインタでは無いのでエラー


もし、Cの構造体やポインタについての理解が不十分なら、一度復習することをお勧めします。

若干語弊があるのですが。
C++のクラス、というのは、Cの構造体を拡張したものと考えてください。

> (1) *devide = createDevice( ...);

createDeviceの宣言を見てないのですが、IrrlichtDevice へのポインタを返す関数になってませんか?
Cでも
struct A * foo(~)
とかいう風に構造体(struct A)へのポインタを返す関数ってありますよね?

> (2) if(!device)
ポインタは NULL なら 「偽」、そうでないなら「真」です。
!は論理値の真偽を反転させます。
これはCでもよく使われる記法です。

例)
FILE *fp = fope...続きを読む

Qchar AA[]{"全角文字"};から"全"という一字を取り出したい

 今晩は、Cの初心者です、宜しくお願いします。
 全角文字の入ったchar AA[]{"全角文字"};から"全"という文字一字を取り出す時にAA[0]とかくとエラーになります。
 どのようにしたら取り出せるのでしょう。
 ポインタを使う方法と使わない方法を教えて下さい。
 宜しくお願いします。

Aベストアンサー

お疲れ様です。

まずお伺いしたのがOSおよび開発するためのコンパイラです。

ロケール等の話は分かりませんが、昔のC言語で日本語を扱う場合には全角文字1文字で2個つのchar領域を使用していました。
(マルチバイト文字セットと言います。)

詳細は参考URLを参照の事。

windowsでVCと仮定した場合、charを使われていると言うことは、多分、shift-jis(シフトJIS)で文字列を扱っていると思われます。

結論として全角文字1文字だけを取り出したいという場合は、結局char2個分のデータを取り出す必要があります。

>char AA[]={'全','角'};

char AA[]="全角";
とし
>printf("%s%s\n" , AA[0],AA[1] ) ;

printf("%c%c\n" , AA[0],AA[1] ) ;
とすれば、「全」だけを表示する事が可能と思われます。

日本語を文字列で表示する為の文字コードについては
Shift-JISだけでなく、UnicodeやUTF・EUC・JISなどがあります。

もう少し詳しく記載してあるホームページはないか探してみましたが、ちょっと無理でした。

参考URL:http://marupeke296.com/CPP_charUnicodeWideChar.html

お疲れ様です。

まずお伺いしたのがOSおよび開発するためのコンパイラです。

ロケール等の話は分かりませんが、昔のC言語で日本語を扱う場合には全角文字1文字で2個つのchar領域を使用していました。
(マルチバイト文字セットと言います。)

詳細は参考URLを参照の事。

windowsでVCと仮定した場合、charを使われていると言うことは、多分、shift-jis(シフトJIS)で文字列を扱っていると思われます。

結論として全角文字1文字だけを取り出したいという場合は、結局char2個分のデータを取り出...続きを読む

Q構造体のメンバにファイルポインタがあるときの初期化について

#include<stdio.h>
typedef struct file{
FILE *fp;
char filename[255];
int flag;
}sFILE;
main()
{
sFILE fp={ ,"output.txt",1100};
}

のように書きたいんですが、sFILE fp={ ,"output.txt",1100};の最初のファイルポインタのところは何を入れたらいいんでしょうか?

Aベストアンサー

正直、構造体に FILEポインタ持たせる利点が分からないのだけど、
とりあえず NULL でいいんじゃないでしょうか、。

こんな感じ
sFILE fp={NULL,"output.txt",1100};

Q「void ( *signal(int sig, void (*func)(int)) ) (int)」の (int)

signal関数の書式についてですが、

  void ( *signal(int sig, void (*func)(int)) ) (int);

最後に付く(int)は一体何でしょうか?
このような関数の書式ははじめて見ました。
UNIX系の何かでしょうか。
回答よろしくお願いします。

Aベストアンサー

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t sighandler);
より後半部分のtypedefを置き換えると
sighandler_t signal(int signum, void (*sighandler)(int));
つぎに戻り値の部分のtypedefを置き換えると
void (*signal(int signum, void (*sighandler)(int)))(int);
となります。
(
sighandler_t signal(int signum, void (*sighandler)(int));
の「signal(int signum, void (*sighandler)(int))」をAと置き換えて
sighandler_t A;
からtypedefを置き換えると
void (*A)(int);
となり、Aを戻すと
void (*signal(int signum, void (*sighandler)(int)))(int);
となる。
)

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t sighandler);
より後半部分のtypedefを置き換えると
sighandler_t signal(int signum, void (*sighandler)(int));
つぎに戻り値の部分のtypedefを置き換えると
void (*signal(int signum, void (*sighandler)(int)))(int);
となります。
(
sighandler_t signal(int signum, void (*sighandler)(int));
の「signal(int signum, void (*sighandler)(int))」をAと置き換えて
sighandler_t A;
からtypedefを置き換...続きを読む


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング