zoukankan      html  css  js  c++  java
  • 如何將輸入的字串存到記憶體後,再一起印出來? (C/C++) (C)

    Abstracion
    最近有同學問我這個問題,整理之後,將心得提出與大家分享。

    Introduction
    學習C/C++時,一開始要學的就是標準輸入輸出。一個很簡單的需求:由鍵盤輸入字串存入記憶體,若輸入了quit,則結束,最後在全部已經存在記憶體中的字串。先看看C++要怎麼寫。

    C++ / string_into_svec.cpp

    1 /* 
    2 (C) OOMusou 2008 http://oomusou.cnblogs.com
    3 
    4 Filename    : string_into_svec.cpp
    5 Compiler    : Visual C++ 8.0
    6 Description : Demo how to use string & vector in C++
    7 Release     : 03/21/2008 1.0
    8 */
    9 #include <iostream>
    10 #include <string>
    11 #include <vector>
    12 
    13 using namespace std;
    14 
    15 int main() {
    16   string s;
    17   vector<string> svec;
    18  
    19   while(1) {
    20     cin >> s;
    21     if (s == "quit")
    22       break;
    23      
    24     svec.push_back(s);
    25   }
    26  
    27   vector<string>::iterator iter = svec.begin();
    28   for(; iter != svec.end(); ++iter)
    29     cout << *iter << endl;
    30 }


    執行結果

    Hello World
    Hello C++
    quit
    Hello
    World
    Hello
    C++


    既然用C++,當然使用較好用的std::string與std::vector,一切程式都很直觀,不過既然要用STL,若能用std::copy()就更精簡了。

    C++ / string_into_svec_stl.cpp

    1 /* 
    2 (C) OOMusou 2008 http://oomusou.cnblogs.com
    3 
    4 Filename    : string_into_svec_stl.cpp
    5 Compiler    : Visual C++ 8.0
    6 Description : Demo how to use string & vector in C++ & STL
    7 Release     : 03/21/2008 1.0
    8 */
    9 #include <iostream>
    10 #include <string>
    11 #include <vector>
    12 #include <algorithm>
    13 
    14 using namespace std;
    15 
    16 int main() {
    17   string s;
    18   vector<string> svec;
    19  
    20   while(1) {
    21     cin >> s;
    22     if (s == "quit")
    23       break;
    24      
    25     svec.push_back(s); 
    26   }
    27  
    28   copy(svec.begin(), svec.end(), ostream_iterator<string>(cout, "\n"));
    29 }


    執行結果

    Hello World
    Hello C++
    quit
    Hello
    World
    Hello
    C++


    使用std::copy()後,仍發現一個缺憾,由於cin在擷取字串時,把空格當成分割字串的方式,所以明明輸入的是Hello World一個字串,但卻變成Hello和World兩個字串,所以打算改用getchar(),這樣就能把空格也當成字串的一部分。

    C++ / string_into_svec_space.cpp

    1 /* 
    2 (C) OOMusou 2008 http://oomusou.cnblogs.com
    3 
    4 Filename    : string_into_svec_space.cpp
    5 Compiler    : Visual C++ 8.0
    6 Description : Demo how to use string & vector in C++ with space
    7 Release     : 03/21/2008 1.0
    8 */
    9 #include <iostream>
    10 #include <string>
    11 #include <vector>
    12 #include <stdio.h>
    13 #include <algorithm>
    14 
    15 using namespace std;
    16 
    17 int main() {
    18   string s;
    19   vector<string> svec;
    20   char ch;
    21  
    22   while(1) {
    23     while((ch = getchar()) != '\n') {
    24       s.push_back(ch);
    25     }
    26    
    27     if (s == "quit")
    28       break;
    29    
    30     svec.push_back(s);
    31      
    32     s = "";
    33   }
    34  
    35   copy(svec.begin(), svec.end(), ostream_iterator<string>(cout, "\n"));
    36 }


    執行結果

    Hello World
    Hello C++
    quit
    Hello World
    Hello C++


    使用getchar()後,執行結果如預期,是一個完美的版本。若用純C語言呢?std::string必須改用char [],std::vector必須改成array。

    C語言 / string_into_array_space.c

     1 /* 
     2 (C) OOMusou 2008 http://oomusou.cnblogs.com
     3 
     4 Filename    : string_into_array_space.c
     5 Compiler    : Visual C++ 8.0
     6 Description : Demo how to use char[] & array in C with space
     7 Release     : 03/21/2008 1.0
     8 */
     9 #include <stdio.h>
    10 #include <string.h>
    11 
    12 #define SLEN 255
    13 #define ALEN 255
    14 
    15 int main() {
    16   char s[SLEN];
    17   char sarr[ALEN][SLEN];
    18   char ch;
    19   int j = 0;
    20   int k = 0;
    21   
    22   while(1) {
    23     int i = 0;
    24     while((ch = getchar()) != '\n')
    25       s[i++= ch;
    26  
    27     s[i] = '\0';   
    28     
    29     if (!strcmp(s, "quit"))
    30       break;
    31     else {
    32       strncpy(sarr[j], s, SLEN - 1);
    33       sarr[j++][SLEN - 1= '\0';
    34     }
    35   }
    36   
    37   while(k < j)
    38     printf("%s\n", sarr[k++]);
    39 }

    執行結果

    Hello World
    Hello C++
    quit
    Hello World
    Hello C++


    用C語言改寫後,第一個衝擊就是C語言的字串,C的字串是pointer概念,和其他語言完全不同,還必須配合strcmp()、strncpy()、memset()等函數才能正常運作。C語言最大的特色在於,pointer貫穿整個語言,什麼都可以用pointer寫,既然『你要東方不敗,我就給你東方不敗』,整個程式全部用pointer改寫。

    C語言 / string_into_array_space_pointer.c

     1 /* 
     2 (C) OOMusou 2008 http://oomusou.cnblogs.com
     3 
     4 Filename    : string_into_array_space_pointer.c
     5 Compiler    : Visual C++ 8.0
     6 Description : Demo how to use char[] & array in C with space by pointer
     7 Release     : 03/21/2008 1.0
     8 */
     9 #include <stdio.h>
    10 #include <string.h>
    11 
    12 #define SLEN 255
    13 #define ALEN 255
    14 
    15 int main() {
    16   char s[SLEN];
    17   char sarr[ALEN][SLEN];
    18   char ch;
    19   int j = 0;
    20   int k = 0;
    21   
    22   while(1) {
    23     int i = 0;
    24     while((ch = getchar()) != '\n')
    25       *(s+i++= ch;
    26     
    27     *(s+i) = '\0';
    28     
    29     if (!strcmp(s, "quit"))
    30       break;
    31     else {
    32       strncpy(*(sarr + j), s, SLEN - 1);
    33       *(*(sarr + (j++)) + SLEN - 1= '\0';
    34     }
    35   }
    36   
    37   while(k < j)
    38     printf("%s\n"*(sarr+k++));
    39 }

    執行結果

    Hello World
    Hello C++
    quit
    Hello World
    Hello C++


    全用pointer改寫後,若不熟悉C語言風格的人,一定認為這是天書,其實這只是習慣問題,改用pointer的思考方式,多寫就習慣了。

    不過由此也看到C語言這種靜態語言的本質:『array得事先宣告好大小』,而不能如std::vector那樣有彈性,只要不斷的push_back()就好,C語言要如何才能如std::vector那樣有彈性呢?C語言若要動態,只能靠malloc(),但不是用malloc()來宣告array,而是用malloc()來搭配linked list。

    C語言

    1 /* 
    2 (C) OOMusou 2008 http://oomusou.cnblogs.com
    3 
    4 Filename    : string_into_linkedlist_space.c
    5 Compiler    : Visual C++ 8.0
    6 Description : Demo how to use char[] & linkedlist in C with space
    7 Release     : 03/21/2008 1.0
    8 */
    9 #include <stdio.h>
    10 #include <string.h>
    11 #include <stdlib.h>
    12 
    13 #define SLEN 255
    14 
    15 struct list {
    16   char s[SLEN];
    17   struct list *next;
    18 };
    19 
    20 int main() {
    21   char s[SLEN];
    22   char ch;
    23   struct list *head    = NULL;
    24   struct list *current = NULL;
    25   struct list *prev    = NULL;
    26  
    27   while(1) {
    28     int i = 0;
    29     while((ch = getchar()) != '\n')
    30       *(s+i++) = ch;
    31    
    32     *(s+i) = '\0';
    33    
    34     if (!strcmp(s, "quit"))
    35       break;
    36    
    37     current = (struct list *)malloc(sizeof(struct list));
    38     if (current == NULL)
    39       exit(EXIT_FAILURE);
    40        
    41     current->next = NULL;
    42      
    43     strncpy(current->s, s , SLEN -1);
    44     current->s[SLEN -1] = '\0';
    45      
    46     if (head == NULL)
    47       head = current;
    48     else
    49       prev->next = current;
    50        
    51     prev = current;
    52     memset(s, '\0', sizeof(s));
    53   }
    54  
    55   // display linked list
    56   current = head;
    57   while(current != NULL) {
    58     printf("%s\n", current->s);
    59     current = current->next;
    60   }
    61  
    62   // free linked list
    63   current = head;
    64   while(current != NULL) {
    65     prev = current;
    66     current = current->next;
    67     free(prev);
    68   }
    69 }

    執行結果

    Hello World
    Hello C++
    quit
    Hello World
    Hello C++


    改用linked list後,就和std::vector一樣有彈性了,缺點就是程式碼稍長了些。

    Conclusion
    有很長一段時間,我一直很懷疑學資料結構要幹嘛?也聽到很多專業工程師,不會資料結構一樣表現的很好,問題出在哪裡呢?原來現在大部分的語言,library和framework都相當完善,都已經將常用的資料結構和演算法內建了,所以你只要會用就好,根本不需自己重新創造輪子,如C++有STL,C#有.NET Framework,Java有J2SE...等,但若你用的是C語言,由於標準library有限,所以資料結構就顯得非常重要,在上例可以看出,C語言沒有C++的std::vector可用,只好拿出資料結構的看家本領linked list了。所以資料結構並非不重要,只是現在語言越來越高階,library越來越齊全,導致實務上使用資料結構的機會越來越少,但若你今天只有C語言可用(如8051、嵌入式系統、Linux kernel)時,這就是資料結構發光發熱的地方了

  • 相关阅读:
    hadoop hdfs总结 NameNode部分 概述
    最近近况
    hadoop hdfs总结 NameNode部分 1
    rsync 使用
    SmartHost
    hadoop unit test 问题
    git 使用记录
    java 类内存分配计算
    hadoop hdfs总结 NameNode部分 2
    0417 430调试技巧
  • 原文地址:https://www.cnblogs.com/lzjsky/p/1861787.html
Copyright © 2011-2022 走看看