質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

2回答

713閲覧

sprintf関数の第3引数の値が勝手に変わってしまう

kappamaking

総合スコア2

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2022/10/31 15:01

編集2022/10/31 15:02

スタックを使って木構造を走査するプログラムをC言語で書いているのですが、sprintf関数の前後で、文字列dirの値が結合した後の文字列に変わってしまい、うまく動作しません(dir="a/b",filename="c"でspritf(path,"%s/%s",dir,filename)とした場合はdirがa/b/cに変わってしまう)。strcat関数を使った場合も同様でした。値が変わらないようにする方法はありませんか?
ソースコードは一部省略しています。

ソースコード

C言語

1void printdir(char *dir){ 2 char *filename; 3 char path[512]; 4 struct dirent **list; 5 int idx; 6 7 /*- 編集 -*/ 8 struct st{ 9 struct dirent **l; 10 int i; 11 char *p; 12 }; 13 14 int last=-1; 15 struct st *stack[50]; 16 struct st *node; 17 18 struct st *getSt(){ 19 struct st *p=(struct st*)malloc(sizeof(struct st)); 20 if(p==NULL){ 21 printf("Malloc Error.\n"); 22 exit(1); 23 } 24 p->i=0; 25 p->p=""; 26 27 return p; 28 } 29 30 node=getSt(); 31 node->l=dopen(dir); 32 node->p=dir; 33 push(node); 34 35 while( !is_empty() ){ 36 37 /*- 編集 -*/ 38 node=pop(); 39 list=node->l; 40 idx=node->i; 41 dir=node->p; 42 43 while( ( filename = dread( list[idx++] ) ) != NULL ){ 44 sprintf( path, "%s/%s", dir, filename ); 45 46 if( !dirp( path ) ){ 47 printf("%s\n", path ); 48 49 }else{ 50 51 /*- 編集 -*/ 52 node->i=idx; 53 push(node); 54 node=getSt(); 55 node->l=dopen(path); 56 node->p=path; 57 push(node); 58 break; 59 } 60 } 61 } 62} 63

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jimbe

2022/10/31 16:50 編集

struct st の p の扱いが変では。 それと、コードは省略は仕方ない場合もありますが、出来るだけ実行して現象が再現できるものをご提示ください。 原因が分からない場合、省略された部分が原因の場合もあります。
setoppu

2022/10/31 22:20 編集

sprint()コールする前に、それぞれのアドレスをprintf()で表示してみてはどうです? printf("dir=%p[%s]/filename=%p[%s]\n", dir, dir, filename, filename); みたいな。 あとは…それぞれの領域が十分なサイズがあるのか?でしょうかね。 ループ中にp->pに入るのがみんな同じアドレス(しかもローカル変数なので関数抜けると保証されない)は既に回答で指摘されていますが。
guest

回答2

0

ベストアンサー

スタック内に保存するパスは全て違うのですから struct st 毎に領域が必要なのに、全て path になってしまっています。
struct st のメンバ p は char ポインタではなく char 配列とし、 path の内容をコピーして保存することになるのでは無いでしょうか。(alloc してもいいですけど。)


struct st の要素の使い方よりも、全体的に妙なことになっています。
st.l が dirent 配列としても st.i は必要無いはずです。(dopen とか dread がどういうモノなのかはっきりしませんが。)
スタックにはパスだけあれば十分だと思います。

c

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4#include <dirent.h> 5#include <sys/stat.h> 6 7typedef struct { 8 char path[512]; 9} StackEntry; 10 11typedef struct { 12 int top; 13 int capa; 14 StackEntry **entries; 15} Stack; 16 17Stack *allocStack() { 18 Stack *stack = malloc(sizeof(Stack)); 19 memset(stack, 0, sizeof(Stack)); 20 return stack; 21} 22 23void freeStack(Stack *stack) { 24 if(stack != NULL) { 25 if(stack->entries != NULL) { 26 for(int i=0; i<stack->top; i++) freeEntry(stack->entries[i]); 27 free(stack->entries); 28 } 29 free(stack); 30 } 31} 32 33void pushStack(Stack *stack, StackEntry *entry) { 34 if(stack->top == stack->capa || stack->entries == NULL) { 35 int capa = stack->capa + 10; 36 StackEntry **p = realloc(stack->entries, sizeof(StackEntry *) * capa); 37 if(p == NULL) { 38 printf("pushStack: realloc error."); 39 exit(1); 40 } 41 stack->capa = capa; 42 stack->entries = p; 43 } 44 stack->entries[stack->top++] = entry; 45} 46 47StackEntry *popStack(Stack *stack) { 48 if(stack == NULL || stack->top == 0) return NULL; 49 return stack->entries[--stack->top]; 50} 51 52StackEntry *allocEntry(char *path) { 53 StackEntry *entry = malloc(sizeof(StackEntry)); 54 if(entry == NULL) { 55 printf("createEntry: malloc error."); 56 exit(1); 57 } 58 strcpy(entry->path, path); 59 return entry; 60} 61 62void freeEntry(StackEntry *entry) { 63 if(entry != NULL) free(entry); 64} 65 66int isDirectory(char *path) { 67 struct stat st; 68 if(stat(path, &st)) return 0; //false 69 return (st.st_mode & S_IFMT) == S_IFDIR; 70} 71 72void printdir(char *path){ 73 if(!isDirectory(path)) { 74 printf("file: %s\n", path); 75 return; 76 } 77 78 Stack *stack = allocStack(); 79 pushStack(stack, allocEntry(path)); 80 81 for(StackEntry *parent; (parent=popStack(stack)) != NULL; freeEntry(parent)) { 82 printf("parent->path=%s\n", parent->path); 83 DIR *dir = opendir(parent->path); 84 85 for(struct dirent *de; (de=readdir(dir)) != NULL; ) { 86 printf("de->d_name=%s\n", de->d_name); 87 if(de->d_name[0] == '.') continue; //"."(カレント),".."(親)および'.'で始まる隠しファイルは無視 88 89 char childpath[1024]; 90 sprintf(childpath, "%s\\%s", parent->path, de->d_name); 91 if(isDirectory(childpath)) { 92 printf("directory: %s\n", childpath); 93 pushStack(stack, allocEntry(childpath)); 94 } else { 95 printf("file: %s\n", childpath); 96 } 97 } 98 99 closedir(dir); 100 } 101 102 freeStack(stack); 103} 104 105int main(int argc, char *argv[]) { 106 if(argc != 2) { 107 fprintf(stderr, "Usage: %s <directory-path>\n", argv[0]); 108 exit(1); 109 } 110 printdir(argv[1]); 111}

フォルダ構成
フォルダのツリーの画像

実行結果

plain

1> printdir F:\teratail\teratail\aaa 2parent->path=F:\teratail\teratail\aaa 3de->d_name=. 4de->d_name=.. 5de->d_name=a1.txt 6file: F:\teratail\teratail\aaa\a1.txt 7de->d_name=a2.txt 8file: F:\teratail\teratail\aaa\a2.txt 9de->d_name=bbb 10directory: F:\teratail\teratail\aaa\bbb 11de->d_name=zzz 12directory: F:\teratail\teratail\aaa\zzz 13parent->path=F:\teratail\teratail\aaa\zzz 14de->d_name=. 15de->d_name=.. 16de->d_name=z1.txt 17file: F:\teratail\teratail\aaa\zzz\z1.txt 18parent->path=F:\teratail\teratail\aaa\bbb 19de->d_name=. 20de->d_name=.. 21de->d_name=b1.txt 22file: F:\teratail\teratail\aaa\bbb\b1.txt

投稿2022/10/31 21:05

編集2022/11/02 02:02
jimbe

総合スコア12648

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kappamaking

2022/11/02 00:35

ご回答ありがとうございます。 stのメンバpを毎回mallocするようにしたところ解決しました。 dopenやらは教授が用意してくれた関数のようで、細かい挙動は私も把握できておりません...()
guest

0

dir=node->p
node->p=path;

dir と path が同じアドレスを指してませんか ?

投稿2022/10/31 15:24

ruruucky

総合スコア18

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kappamaking

2022/11/02 00:37

ご回答ありがとうございます。 ご指摘の点を直したところ解決しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問