現在、C言語を勉強しています
現在、読み取り用のファイルからデータを読み取って情報を処理し、別のファイルにその結果を書き込むといったことをしています。
その中で、配列変数を用いた並べ替えに悪戦苦闘しています。
数字を並べ替えるのと、文字を並べ替えるのでは方法が違うとのこと。
そもそも、文字を並べ替えるとはどういうことですか?
まだ経験が少ないので、できる限りわかりやすく説明して下さい。
(c言語に使用する言語を使われてもかまいません。)

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

A 回答 (4件)

直接の回答ではありませんが、KOH_daさんのプログラム例だとまずい点があるので、念のため指摘しときます。


数値の入れ替えの方はそのままでもいいんですが、文字列の方は必ずしも文字列の記憶領域が十分確保されているとは限りませんから、単にポインタを入れ替えるにとどめるか、もしくはきちんとmalloc/freeしないとだめですよね。

なので、前者(ポインタをただ入れ替えるだけ)なら、

if( strcmp( a[i], a[j] ) > 0 ) {
 w = a[i];
 a[i] = a[j];
 a[j] = w;
}

でしょうし、また後者(完全にmalloc/freeしなおす)なら

if( strcmp( a[i], a[j] ) > 0 ) {
 w = malloc( strlen( a[i] ) + 1 );
 strcpy( w, a[i] );
 realloc( a[i], strlen( a[j] ) + 1 );
 strcpy( a[i], a[j] );
 realloc( a[j], strlen( w ) + 1 );
 strcpy( a[j], w );
 free( w );
}

と書かないと、最悪の場合配列の他の部分の文字列が破壊されるなど大変なことになります。

しかも後者の場合だと、今回はあえて省略しましたが、malloc/reallocに失敗した場合のエラー処理まで考えると処理が非常に重くなります。
なので、前者のような書き方がベストでは、と思いますが。
    • good
    • 0
この回答へのお礼

質問が抽象的だったようですね。すみませんでした。
とても詳しく説明していただいてありがとうございました。

お礼日時:2001/03/16 10:56

答えじゃなくて、問題の意味を聞かれても推測でしか答えられません。


たぶん文字を並べ替えるというのは、
文字列を並べ替えるという意味だと思います。
名前を五十音順にするとか...。

で、方法が違うというのはこういうことじゃないかな。
数字の並べ替えだと...
if( a[i] < a[j] ) {
w = a[i];
a[i] = a[j];
a[j] = w;
}
というように並べ替えることができます。
しかし文字列だとそのまま比較することができませんし、
代入にも専用の関数が必要になります。
if( strcmp(a[i], a[j]) > 0 ) {
strcpy( w, a[i] );
strcpy( a[i], a[j] );
strcpy( a[j], w ) ;
}
    • good
    • 0
この回答へのお礼

質問が抽象的だったようですね。すみませんでした。
参考になりました。ありがとうございました。

お礼日時:2001/03/16 10:57

正確には「文字を並べ替える」ではなく、「文字列を辞書順に並べる」と表現すると意味が通じると思います。



基本的には数値同士の比較であれば、単純にif文等で比較してやればいいんですが、文字列同士の比較の場合はstrcmp関数を使うのが普通です。
ただし、strcmp関数はあくまで8bitコード(半角英数字、半角カナ)の文字列で利用されることを前提としているため、漢字混じり文字列(つまりマルチバイトコード)の場合はwcscmp関数などを使う必要があります。
また漢字を扱う場合はそのコード体系(JIS、Shift-JIS、EUC)の違いにも注意する必要があり、特に比較や並べ替えを行う場合は事前に漢字コードを何らかの形で統一しておかないと、訳の分からない結果がでてくる原因につながります。

今制作中というプログラムが具体的にどこまでの処理を予定しているのかがわからないのでこれ以上の回答は難しいですが…。
    • good
    • 0
この回答へのお礼

わかりやすい回答ありがとうございました。
質問が抽象的だったようですね。すみませんでした。

お礼日時:2001/03/16 10:59

ここで並べ替えとは、どういう処理をさしているのでしょうか?


ソーティング(整列)ですか?そうだと仮定して…

「方法が違うとのこと」とされていますが、整列そのものの原理は、
対象が何であれ変わるわけではありません。数値と文字列(文字で
はなくて文字列ですよね?)で違うのは、代入するのに = を使う
か strcpy 等を使うかの違いと、比較するのに <, =, > を使うか、
strcmp 等を使うかの違いです。もっとも、文字列の比較の場合、
何を大きいとするかは目的によって違いますので、特殊な順序にし
たいなら新たに関数を用意しなければいけません。
    • good
    • 0

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

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

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

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

Q[C言語]三目並べ

三目並べのプログラムで、以下のようなコンピュータの思考ルーチンを作っている所なのですが、
/* 後手で先手に初めに真ん中に置かれたら角に置く */
/* 後手で先手に初めに角に置かれたら真ん中に置く */
この二つがうまくいかないようで困っています。どこか間違っているのでしょうか?

void com( char te )
{
int total,kado,aite,a,tate,yoko,ok = 0;

/*
0 = 空 te = 1(○) → aite = 2(×)
1 = ○ te = 2(×) → aite = 1(○)
2 = ×
*/
/* 勝てる場所を探す */
for ( tate = 0; tate < 3; tate++ ) { /* 横一列 */
if( brd[tate][0] == 0 && brd[tate][1] == te && brd[tate][2] == te ) {
brd[tate][0] = te;
return;
}
if( brd[tate][0] == te && brd[tate][1] == 0 && brd[tate][2] == te ) {
brd[tate][1] = te;
return;
}
if( brd[tate][0] == te && brd[tate][1] == te && brd[tate][2] == 0 ) {
brd[tate][2] = te;
return;
}
}
for ( yoko = 0; yoko < 3; yoko++ ) { /* 縦一列 */
if( brd[0][yoko] == 0 && brd[1][yoko] == te && brd[2][yoko] == te ) {
brd[0][yoko] = te;
return;
}
if( brd[0][yoko] == te && brd[1][yoko] == 0 && brd[2][yoko] == te ) {
brd[1][yoko] = te;
return;
}
if( brd[0][yoko] == te && brd[1][yoko] == te && brd[2][yoko] == 0 ) {
brd[2][yoko] = te;
return;
}
}
if( brd[0][0] == 0 && brd[1][1] == te && brd[2][2] == te ) { /* 斜め1 */
brd[0][0] = te;
return;
}
if( brd[0][0] == te && brd[1][1] == 0 && brd[2][2] == te ) {
brd[1][1] = te;
return;
}
if( brd[0][0] == te && brd[1][1] == te && brd[2][2] == 0 ) {
brd[2][2] = te;
return;
}
if( brd[0][2] == 0 && brd[1][1] == te && brd[2][0] == te) { /* 斜め2 */
brd[0][2] = te;
return;
}
if( brd[0][2] == te && brd[1][1] == 0 && brd[2][0] == te) {
brd[1][1] = te;
return;
}
if( brd[0][2] == te && brd[1][1] == te && brd[2][0] == 0) {
brd[2][0] = te;
return;
}

/* 相手の勝ちを阻止する */

aite = te % 2 + 1;
for ( tate = 0; tate < 3; tate++ ) { /* 横一列 */
if( brd[tate][0] == 0 && brd[tate][1] == aite && brd[tate][2] == aite){
brd[tate][0] = te;
return;
}
if( brd[tate][0] == aite && brd[tate][1] == 0 && brd[tate][2] == aite){
brd[tate][1] = te;
return;
}
if( brd[tate][0] == aite && brd[tate][1] == aite && brd[tate][2] == 0){
brd[tate][2] = te;
return;
}
}
for ( yoko = 0; yoko < 3; yoko++ ) { /* 縦一列 */
if( brd[0][yoko] == 0 && brd[1][yoko] == aite && brd[2][yoko] == aite){
brd[0][yoko] = te;
return;
}
if( brd[0][yoko] == aite && brd[1][yoko] == 0 && brd[2][yoko] == aite){
brd[1][yoko] = te;
return;
}
if( brd[0][yoko] == aite && brd[1][yoko] == aite && brd[2][yoko] == 0){
brd[2][yoko] = te;
return;
}
}
if( brd[0][0] == 0 && brd[1][1] == aite && brd[2][2] == aite){ /* 斜め1 */
brd[0][0] = te;
return;
}
if( brd[0][0] == aite && brd[1][1] == 0 && brd[2][2] == aite ) {
brd[1][1] = te;
return;
}
if( brd[0][0] == aite && brd[1][1] == aite && brd[2][2] == 0 ) {
brd[2][2] = te;
return;
}
if( brd[0][2] == 0 && brd[1][1] == aite && brd[2][0] == aite){ /* 斜め2 */
brd[0][2] = te;
return;
}
if( brd[0][2] == aite && brd[1][1] == 0 && brd[2][0] == aite) {
brd[1][1] = te;
return;
}
if( brd[0][2] == aite && brd[1][1] == aite && brd[2][0] == 0) {
brd[2][0] = te;
return;
}

/* 後手で先手に初めに角に置かれたら真ん中に置く */
if ( te == 2 ) {
for ( a = 0; a < 9; a++ ) {
total += brd[a/3][a%3];
}
kado = brd[0][0] + brd[0][2] + brd[2][0] + brd[2][2];
if ( total == 1 && kado ==1){
brd[1][1] = te;
return;
}
}

/* 後手で先手に初めに真ん中に置かれたら角に置く */
if ( te == 2 ) {
for ( a = 0; a < 9; a++ ) {
total += brd[a/3][a%3];
}
if ( total == 1 && brd[1][1] == aite){
brd[0][0] = te;
return;
}
}


/* ランダム */
srandomdev();
do {
a = random() % 9;
tate = a/3;
yoko = a%3;
if ( brd[tate][yoko] == 0 ) {
ok = 1;
}
} while ( ok == 0 );

/* 盤面に書き込み */
brd[tate][yoko] = te;
}

三目並べのプログラムで、以下のようなコンピュータの思考ルーチンを作っている所なのですが、
/* 後手で先手に初めに真ん中に置かれたら角に置く */
/* 後手で先手に初めに角に置かれたら真ん中に置く */
この二つがうまくいかないようで困っています。どこか間違っているのでしょうか?

void com( char te )
{
int total,kado,aite,a,tate,yoko,ok = 0;

/*
0 = 空 te = 1(○) → aite = 2(×)
1 = ○ te = 2(×) → aite = 1(○)
2 = ×
*/
/* 勝てる場所を探す...続きを読む

Aベストアンサー

totalの初期値が設定されていないからでは?

QC言語のソースをC++言語に変換したい

C言語で書かれていたソースをC++言語に変換したいのですが
どのような点に気をつければよいでしょうか

現在、プログラムの主な構造は構造体とそれを扱う関数が実装されていて、
これらをクラスを使用して書き換えようと思います。
それ以外に気にしておくものはありますか。

例えば、ヘッダファイルで<stdio.h>をインクルードしているところがありますが、
これは<cstdio>に書き換えたほうがよいかもしれない、と言われたことはあります。
printfなどはprintfのまま使用しても大丈夫ですか。
std::printfに書き換えたり、iostreamを使用する方法に書き換えたほうがいいですか。
規格としてはどのようになっているのでしょうか。
(「過去との互換性のためにあるだけであり、非推奨」とかあったりしますか。)

Aベストアンサー

まず <stdio.h> などは言われるように「非推奨」なので「最終的には変更する」ことを前提にした方がいいでしょうね (たぶん C++1y までは大丈夫だと思うけど). とはいえ, 単純に
<cstdio> を #include しててきとうに std:: を付ける
だけでもだいたいいけますが. あえて <iostream> に直す必要はないです.

まあ, ヘッダ以外は「とりあえず拡張子だけ変えてコンパイルエラーが出たら考える」という行きあたりばったりな方法でもなんとかなっちゃいますけどね.

QC言語 並び替え(配列)について

10個の整数を
昇順に並び替える
プログラムを
出来るだけ簡単に
使う関数は少なく
出来ないでしょうか?

宜しくお願い致します。

Aベストアンサー

これはどうですか?

#include <stdio.h>

void main(){

int d[10], i, j, work;

for(i=0; i<10; i++){
printf("d[%d]->", i);
scanf("%d", &d[i]);
}

for(i=0; i<=8; i++){
for(j=i+1; j<=9; j++){
if(d[i]>d[j]){
work=d[i];
d[i]=d[j];
d[j]=work;
}
}
}

for(i=0; i<10; i++){
printf("d[%d]:%d\n", i, d[i]);
}
}

Qファイルを辞書順に並べ替えるプログラム c言語

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

#define NAME_LEN 64
#define NUM_LEN 16

typedef struct contact{
char name[NAME_LEN];
char num[NUM_LEN];
struct contact *left;
struct contact *right;
} Contact;

void mk_tree(Contact *p, Contact c)
{
if(strcmp(p->name, c.name) > 0){
if(p->left == NULL)
p->left = &c;
else mk_tree(p->left, c);
}
else if(strcmp(p->name, c.name) < 0){
if(p->right == NULL)
p->right = &c;
else mk_tree(p->right, c);
}
else {
if(strcmp(p->num, c.num) > 0){
if(p->left == NULL)
p->left = &c;
else mk_tree(p->left, c);
}
else {
if(p->right == NULL)
p->right = &c;
else mk_tree(p->right, c);
}
}
}

void put_dic(Contact *p)
{
if(p->left != NULL){
put_dic(p->left);
}
printf("%s %s\n", p->name, p->num);

if(p->right != NULL)
put_dic(p->right);
}

int main(void)
{
FILE *sfp;
char sname[FILENAME_MAX];
Contact c[100];
Contact *p;
int n = 0;

p = c;

printf("データが入っているファイル名\n"); scanf("%s", sname);

if((sfp = fopen(sname, "r")) == NULL)
printf("データが入っているファイルをオープンできません。\n");
else{
while(fscanf(sfp, "%s%s", c[n].name, c[n].num) == 2){
if(n >= 1)
mk_tree(c, c[n]);
n++;
}
put_dic(p);
fclose(sfp);
}
return 0;
}

上記のプログラムを実行すると、関数mk_treeを3回呼び出した後プログラムが停止してしまいます。

なぜですか。

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

#define NAME_LEN 64
#define NUM_LEN 16

typedef struct contact{
char name[NAME_LEN];
char num[NUM_LEN];
struct contact *left;
struct contact *right;
} Contact;

void mk_tree(Contact *p, Contact c)
{
if(strcmp(p->name, c.name) > 0){
if(p->left == NULL)
p->left = &c;
else mk_tree(p->left, c);
}
else if(strcmp(p->name, c.name) < 0){
if(p->right == NULL)
...続きを読む

Aベストアンサー

本題は #1 の通りでしょう.

あとついでにいうと mk_tree の中の
p->left = &c;
などは右辺でアドレスを取っている c が (関数の仮引数なので) 関数にローカルな自動変数の扱いになります. だから, この文で設定しているアドレスは (関数から出てしまうと) 有効なアドレスではありません.

QC言語の課題で困っています。その1.四則演算

二つの整数値を読み込んで、前者を後者で割り、その結果の商と余りを表示するプログラムを作成。
実行例にあるよう、ゼロで割るような場合への対処も考慮する。

実行例1:
整数の除算を行います。整数を入力してください。
整数A:13
整数B:5
13 ÷ 5 = 2 あまり 3

実行例2:
整数の除算を行います。整数を入力してください。
整数A:10
整数B:0
0でわることはできません!
(注)プログラム実行時にキーボードからどんな整数を入力してもいいように作成すること。

という課題に取り組んでいますが、途中までしか記述できません。
どなたか助けてください。

下記が途中までの記述です。

/*二つの整数値を読み込んで、前者を後者で割り、その結果の商と余りを表示*/
#include <stdio.h>
int main(void)
{
int na, nb;
printf("shimasaki kazunori \n");
puts("整数の除算を行います。整数を入力してください。: \n");
printf("整数A:"); scanf("%d", &na);
printf("整数B:"); scanf("%d", &nb);
printf("na ÷ nb = %d あまり %d \n", na / nb, nb, na % nb);
return(0);
}

二つの整数値を読み込んで、前者を後者で割り、その結果の商と余りを表示するプログラムを作成。
実行例にあるよう、ゼロで割るような場合への対処も考慮する。

実行例1:
整数の除算を行います。整数を入力してください。
整数A:13
整数B:5
13 ÷ 5 = 2 あまり 3

実行例2:
整数の除算を行います。整数を入力してください。
整数A:10
整数B:0
0でわることはできません!
(注)プログラム実行時にキーボードからどんな整数を入力してもいいように作成すること。

という課題に取り組んでいますが、途中までしか記...続きを読む

Aベストアンサー

if (nb == 0) {
printf("0でわることはできません!");
} else {
printf("na ÷ nb = %d あまり %d \n", na / nb, na % nb);
}


人気Q&Aランキング

おすすめ情報