質問編集履歴

4

みす

2020/07/29 07:22

投稿

yukikona
yukikona

スコア12

test CHANGED
@@ -1 +1 @@
1
- aaaac言語でprintfで\nを入れるとなぜか二回出力される
1
+ c言語でprintfで\nを入れるとなぜか二回出力される
test CHANGED
File without changes

3

ffffffffff

2020/07/29 07:22

投稿

yukikona
yukikona

スコア12

test CHANGED
@@ -1 +1 @@
1
- c言語でprintfで\nを入れるとなぜか二回出力される
1
+ aaaac言語でprintfで\nを入れるとなぜか二回出力される
test CHANGED
@@ -14,6 +14,20 @@
14
14
 
15
15
  ```c
16
16
 
17
+ struct stack{
18
+
19
+ char path[100];
20
+
21
+ struct stack *next;
22
+
23
+ };
24
+
25
+ struct stack Topad;
26
+
27
+ struct stack *topad;
28
+
29
+
30
+
17
31
  topad=&Topad;
18
32
 
19
33
  struct stack *newstr;
@@ -90,6 +104,756 @@
90
104
 
91
105
 
92
106
 
107
+ ### 全体のソースコード
108
+
109
+ ```c
110
+
111
+ #include <stdio.h>
112
+
113
+ #include <stdlib.h>
114
+
115
+ #include <sys/types.h>
116
+
117
+ #include <unistd.h>
118
+
119
+ #include <sys/wait.h>
120
+
121
+ #include <string.h>
122
+
123
+
124
+
125
+ /*
126
+
127
+ * 定数の定義
128
+
129
+ */
130
+
131
+
132
+
133
+ #define BUFLEN 1024 /* コマンド用のバッファの大きさ */
134
+
135
+ #define MAXARGNUM 256 /* 最大の引数の数 */
136
+
137
+
138
+
139
+
140
+
141
+ /*
142
+
143
+ * ローカルプロトタイプ宣言
144
+
145
+ */
146
+
147
+
148
+
149
+ int parse(char [], char *[]);
150
+
151
+ void execute_command(char *[], int);
152
+
153
+ void cd_command(char *[]);
154
+
155
+ void pushd_command(char *[]);
156
+
157
+ void dirs_command(char *[]);
158
+
159
+ void popd_command(char *[]);
160
+
161
+ void history_command(char *[]);
162
+
163
+
164
+
165
+ struct stack{
166
+
167
+ char path[100];
168
+
169
+ struct stack *next;
170
+
171
+ };
172
+
173
+ struct stack Topad;
174
+
175
+ struct stack *topad;
176
+
177
+
178
+
179
+
180
+
181
+ /*----------------------------------------------------------------------------
182
+
183
+ *
184
+
185
+ * 関数名 : main
186
+
187
+ *
188
+
189
+ * 作業内容 : シェルのプロンプトを実現する
190
+
191
+ *
192
+
193
+ * 引数 :
194
+
195
+ *
196
+
197
+ * 返り値 :
198
+
199
+ *
200
+
201
+ * 注意 :
202
+
203
+ *
204
+
205
+ *--------------------------------------------------------------------------*/
206
+
207
+
208
+
209
+ int main(int argc, char *argv[])
210
+
211
+ {
212
+
213
+ char command_buffer[BUFLEN]; /* コマンド用のバッファ */
214
+
215
+ char *args[MAXARGNUM]; /* 引数へのポインタの配列 */
216
+
217
+ int command_status; /* コマンドの状態を表す
218
+
219
+ command_status = 0 : フォアグラウンドで実行
220
+
221
+ command_status = 1 : バックグラウンドで実行
222
+
223
+ command_status = 2 : シェルの終了
224
+
225
+ command_status = 3 : 何もしない */
226
+
227
+ topad=&Topad;
228
+
229
+ struct stack *newstr;
230
+
231
+ newstr = (struct stack*)malloc(sizeof(struct stack));
232
+
233
+ topad->next=newstr;
234
+
235
+
236
+
237
+
238
+
239
+ /*
240
+
241
+ * 無限にループする
242
+
243
+ */
244
+
245
+
246
+
247
+ for(;;) {
248
+
249
+
250
+
251
+ /*
252
+
253
+ * プロンプトを表示する
254
+
255
+ */
256
+
257
+
258
+
259
+ printf("Command : ");
260
+
261
+
262
+
263
+ /*
264
+
265
+ * 標準入力から1行を command_buffer へ読み込む
266
+
267
+ * 入力が何もなければ改行を出力してプロンプト表示へ戻る
268
+
269
+ */
270
+
271
+
272
+
273
+ if(fgets(command_buffer, BUFLEN, stdin) == NULL) {
274
+
275
+ printf("\n");
276
+
277
+ continue;
278
+
279
+ }
280
+
281
+
282
+
283
+ /*
284
+
285
+ * 入力されたバッファ内のコマンドを解析する
286
+
287
+ *
288
+
289
+ * 返り値はコマンドの状態
290
+
291
+ */
292
+
293
+
294
+
295
+ command_status = parse(command_buffer, args);
296
+
297
+
298
+
299
+ /*
300
+
301
+ * 終了コマンドならばプログラムを終了
302
+
303
+ * 引数が何もなければプロンプト表示へ戻る
304
+
305
+ */
306
+
307
+
308
+
309
+ if(command_status == 2) {
310
+
311
+ printf("done.\n");
312
+
313
+ exit(EXIT_SUCCESS);
314
+
315
+ } else if(command_status == 3) {
316
+
317
+ continue;
318
+
319
+ }
320
+
321
+
322
+
323
+ /*
324
+
325
+ * コマンドを実行する
326
+
327
+ */
328
+
329
+
330
+
331
+ execute_command(args, command_status);
332
+
333
+ }
334
+
335
+
336
+
337
+ return 0;
338
+
339
+ }
340
+
341
+
342
+
343
+ /*----------------------------------------------------------------------------
344
+
345
+ *
346
+
347
+ * 関数名 : parse
348
+
349
+ *
350
+
351
+ * 作業内容 : バッファ内のコマンドと引数を解析する
352
+
353
+ *
354
+
355
+ * 引数 :
356
+
357
+ *
358
+
359
+ * 返り値 : コマンドの状態を表す :
360
+
361
+ * 0 : フォアグラウンドで実行
362
+
363
+ * 1 : バックグラウンドで実行
364
+
365
+ * 2 : シェルの終了
366
+
367
+ * 3 : 何もしない
368
+
369
+ *
370
+
371
+ * 注意 :
372
+
373
+ *
374
+
375
+ *--------------------------------------------------------------------------*/
376
+
377
+
378
+
379
+ int parse(char buffer[], /* バッファ */
380
+
381
+ char *args[]) /* 引数へのポインタ配列 */
382
+
383
+ {
384
+
385
+ int arg_index; /* 引数用のインデックス */
386
+
387
+ int status; /* コマンドの状態を表す */
388
+
389
+
390
+
391
+ /*
392
+
393
+ * 変数の初期化
394
+
395
+ */
396
+
397
+
398
+
399
+ arg_index = 0;
400
+
401
+ status = 0;
402
+
403
+
404
+
405
+ /*
406
+
407
+ * バッファ内の最後にある改行をヌル文字へ変更
408
+
409
+ */
410
+
411
+
412
+
413
+ *(buffer + (strlen(buffer) - 1)) = '\0';
414
+
415
+
416
+
417
+ /*
418
+
419
+ * バッファが終了を表すコマンド("exit")ならば
420
+
421
+ * コマンドの状態を表す返り値を 2 に設定してリターンする
422
+
423
+ */
424
+
425
+
426
+
427
+ if(strcmp(buffer, "exit") == 0) {
428
+
429
+
430
+
431
+ status = 2;
432
+
433
+ return status;
434
+
435
+ }
436
+
437
+
438
+
439
+ /*
440
+
441
+ * バッファ内の文字がなくなるまで繰り返す
442
+
443
+ * (ヌル文字が出てくるまで繰り返す)
444
+
445
+ */
446
+
447
+
448
+
449
+ while(*buffer != '\0') {
450
+
451
+
452
+
453
+ /*
454
+
455
+ * 空白類(空白とタブ)をヌル文字に置き換える
456
+
457
+ * これによってバッファ内の各引数が分割される
458
+
459
+ */
460
+
461
+
462
+
463
+ while(*buffer == ' ' || *buffer == '\t') {
464
+
465
+ *(buffer++) = '\0';
466
+
467
+ }
468
+
469
+
470
+
471
+ /*
472
+
473
+ * 空白の後が終端文字であればループを抜ける
474
+
475
+ */
476
+
477
+
478
+
479
+ if(*buffer == '\0') {
480
+
481
+ break;
482
+
483
+ }
484
+
485
+
486
+
487
+ /*
488
+
489
+ * 空白部分は読み飛ばされたはず
490
+
491
+ * buffer は現在は arg_index + 1 個めの引数の先頭を指している
492
+
493
+ *
494
+
495
+ * 引数の先頭へのポインタを引数へのポインタ配列に格納する
496
+
497
+ */
498
+
499
+
500
+
501
+ args[arg_index] = buffer;
502
+
503
+ ++arg_index;
504
+
505
+
506
+
507
+ /*
508
+
509
+ * 引数部分を読み飛ばす
510
+
511
+ * (ヌル文字でも空白類でもない場合に読み進める)
512
+
513
+ */
514
+
515
+
516
+
517
+ while((*buffer != '\0') && (*buffer != ' ') && (*buffer != '\t')) {
518
+
519
+ ++buffer;
520
+
521
+ }
522
+
523
+ }
524
+
525
+
526
+
527
+ /*
528
+
529
+ * 最後の引数の次にはヌルへのポインタを格納する
530
+
531
+ */
532
+
533
+
534
+
535
+ args[arg_index] = NULL;
536
+
537
+
538
+
539
+ /*
540
+
541
+ * 最後の引数をチェックして "&" ならば
542
+
543
+ *
544
+
545
+ * "&" を引数から削る
546
+
547
+ * コマンドの状態を表す status に 1 を設定する
548
+
549
+ *
550
+
551
+ * そうでなければ status に 0 を設定する
552
+
553
+ */
554
+
555
+
556
+
557
+ if(arg_index > 0 && strcmp(args[arg_index - 1], "&") == 0) {
558
+
559
+
560
+
561
+ --arg_index;
562
+
563
+ args[arg_index] = '\0';
564
+
565
+ status = 1;
566
+
567
+
568
+
569
+ } else {
570
+
571
+
572
+
573
+ status = 0;
574
+
575
+
576
+
577
+ }
578
+
579
+
580
+
581
+ /*
582
+
583
+ * 引数が何もなかった場合
584
+
585
+ */
586
+
587
+
588
+
589
+ if(arg_index == 0) {
590
+
591
+ status = 3;
592
+
593
+ }
594
+
595
+
596
+
597
+ /*
598
+
599
+ * コマンドの状態を返す
600
+
601
+ */
602
+
603
+
604
+
605
+ return status;
606
+
607
+ }
608
+
609
+
610
+
611
+ /*----------------------------------------------------------------------------
612
+
613
+ *
614
+
615
+ * 関数名 : execute_command
616
+
617
+ *
618
+
619
+ * 作業内容 : 引数として与えられたコマンドを実行する
620
+
621
+ * コマンドの状態がフォアグラウンドならば、コマンドを
622
+
623
+ * 実行している子プロセスの終了を待つ
624
+
625
+ * バックグラウンドならば子プロセスの終了を待たずに
626
+
627
+ * main 関数に返る(プロンプト表示に戻る)
628
+
629
+ *
630
+
631
+ * 引数 :
632
+
633
+ *
634
+
635
+ * 返り値 :
636
+
637
+ *
638
+
639
+ * 注意 :
640
+
641
+ *
642
+
643
+ *--------------------------------------------------------------------------*/
644
+
645
+
646
+
647
+ void execute_command(char *args[], /* 引数の配列 */
648
+
649
+ int command_status) /* コマンドの状態 */
650
+
651
+ {
652
+
653
+ int pid; /* プロセスID */
654
+
655
+ int status; /* 子プロセスの終了ステータス */
656
+
657
+
658
+
659
+
660
+
661
+ /*
662
+
663
+ * 子プロセスを生成する
664
+
665
+ *
666
+
667
+ * 生成できたかを確認し、失敗ならばプログラムを終了する
668
+
669
+ */
670
+
671
+
672
+
673
+ pid = fork ();
674
+
675
+ if(-1==pid){
676
+
677
+ err(EXIT_FAILURE,"can not fork");
678
+
679
+ exit(1);
680
+
681
+ }
682
+
683
+
684
+
685
+ /*
686
+
687
+ * 子プロセスの場合には引数として与えられたものを実行する
688
+
689
+ *
690
+
691
+ * 引数の配列は以下を仮定している
692
+
693
+ * ・第1引数には実行されるプログラムを示す文字列が格納されている
694
+
695
+ * ・引数の配列はヌルポインタで終了している
696
+
697
+ */
698
+
699
+ if(strcmp(args[0],"cd")==0) cd_command(args);
700
+
701
+ else
702
+
703
+ if(strcmp(args[0],"pushd")==0) pushd_command(args);
704
+
705
+ else
706
+
707
+ if(strcmp(args[0],"dirs")==0) dirs_command(args);
708
+
709
+ else
710
+
711
+ if(strcmp(args[0],"popd")==0) popd_command(args);
712
+
713
+ else
714
+
715
+ if(pid==0){
716
+
717
+
718
+
719
+ execvp(*args,args);
720
+
721
+ perror(*args);
722
+
723
+ exit(1);
724
+
725
+ }
726
+
727
+
728
+
729
+ /*
730
+
731
+ * コマンドの状態がバックグラウンドなら関数を抜ける
732
+
733
+ */
734
+
735
+
736
+
737
+ if(command_status==1)return;
738
+
739
+
740
+
741
+ /*
742
+
743
+ * ここにくるのはコマンドの状態がフォアグラウンドの場合
744
+
745
+ *
746
+
747
+ * 親プロセスの場合に子プロセスの終了を待つ
748
+
749
+ */
750
+
751
+
752
+
753
+ /******** Your Program ********/
754
+
755
+ if(pid!=0) wait(&status);
756
+
757
+
758
+
759
+ return;
760
+
761
+ }
762
+
763
+
764
+
765
+ void cd_command(char *args[]){
766
+
767
+ if(args[1]==NULL) chdir(getenv("HOME"));
768
+
769
+ else
770
+
771
+ if(chdir(args[1])==-1) printf("no such directory\n");
772
+
773
+ return;
774
+
775
+ }
776
+
777
+
778
+
779
+ void pushd_command(char *args[]){
780
+
781
+ struct stack *list;
782
+
783
+ struct stack *newstr;
784
+
785
+ list=topad->next;
786
+
787
+ char cwd[BUFLEN];
788
+
789
+ getcwd(cwd,sizeof(cwd));
790
+
791
+
792
+
793
+ if(list->path[0]=='\0'){
794
+
795
+ strcpy(list->path,cwd);
796
+
797
+ list->next=NULL;
798
+
799
+ }else{
800
+
801
+ newstr = (struct stack*)malloc(sizeof(struct stack));
802
+
803
+ strcpy(newstr->path,cwd);
804
+
805
+ topad->next=newstr;
806
+
807
+ newstr->next=list;
808
+
809
+ }
810
+
811
+ return;
812
+
813
+ }
814
+
815
+
816
+
817
+ void dirs_command(char *args[]){
818
+
819
+ struct stack *list;
820
+
821
+ list=topad->next;
822
+
823
+ while(list!=NULL){
824
+
825
+ printf("%s\n",list->path);
826
+
827
+ list=list->next;
828
+
829
+ }
830
+
831
+ return;
832
+
833
+ }
834
+
835
+
836
+
837
+ void popd_command(char *args[]){
838
+
839
+ struct stack *list;
840
+
841
+ list=topad->next;
842
+
843
+ chdir(list->path);
844
+
845
+ topad->next=list->next;
846
+
847
+ list=NULL;
848
+
849
+ }
850
+
851
+
852
+
853
+ /*-- END OF FILE -----------------------------------------------------------*/
854
+
855
+ ```
856
+
93
857
  ###表示内容
94
858
 
95
859
  一回pushdをした後dirsを入力すると

2

わかりやすくした

2020/07/29 07:18

投稿

yukikona
yukikona

スコア12

test CHANGED
@@ -1 +1 @@
1
- printfで\nを入れるとなぜか二回出力される
1
+ c言語でprintfで\nを入れるとなぜか二回出力される
test CHANGED
File without changes

1

みやすくした

2020/07/29 07:10

投稿

yukikona
yukikona

スコア12

test CHANGED
File without changes
test CHANGED
@@ -94,6 +94,8 @@
94
94
 
95
95
  一回pushdをした後dirsを入力すると
96
96
 
97
+ ```
98
+
97
99
  command : pushd
98
100
 
99
101
  command : dirs
@@ -104,9 +106,13 @@
104
106
 
105
107
  comand :
106
108
 
109
+ ```
110
+
107
111
  上のように全く同じ表示が二回されてしまいます
108
112
 
109
113
  また1回pushdしてcd ..してからpushdしさいごにdirsをすると
114
+
115
+ ```
110
116
 
111
117
  Command : pushd
112
118
 
@@ -126,9 +132,13 @@
126
132
 
127
133
  Command :
128
134
 
135
+ ```
136
+
129
137
  という表示になります
130
138
 
131
139
  しかし下から5行目のprintf("%s\n",list->path);の\nをぬいてprintf("%s",list->path)とすると
140
+
141
+ ```
132
142
 
133
143
  Command : pushd
134
144
 
@@ -136,6 +146,8 @@
136
146
 
137
147
  /Users//CLASSES//C/22222Command :
138
148
 
149
+ ```
150
+
139
151
  となり表示数としてはうまくいきます
140
152
 
141
153