[英]Switching letters (no strings or strings functions)
我想每次在文本中將“貓”一詞切換為“狗”。 我不能使用字符串或字符串函數。
我的代碼:
#include <stdio.h>
int main()
{
int i; // loop counter
int size; // size of arry
int input[20];
printf("enter text here\n");
while((input[i] = getchar()) != '\n') // input text to the arry
{
if(input[i]=='c' && input[i+1]=='a' && input[i+2]=='t') // switching characters
{
input[i]='d'; input[i+1]='o'; input[i+2]='g';
}
i++;
size++;
}
i=0; // reset for next loop
while(i <= size) // printing the text out ofthe arry
{
putchar(input[i]);
i++;
}
printf("\n");
return 0;
}
輸出:
enter text here
cat
cat
ȵm�� $$ŵ��p��$���Zտ ��$��M��v��������������������� ������������!��d@8 $
�
�����������5_Segmentation fault
這里的問題很少。
未初始化的局部變量。
int i = 0; // loop counter int size = 0; // size of array
您正在檢查尚未讀取的a
和t
字符。
因此,請檢查當前輸入字符中的t
是否匹配,然后如下所示檢查先前輸入字符中的a
和c
。
if(i>=2 && input[i-2]=='c' && input[i-1]=='a' && input[i]=='t') // switching characters { input[i]='g'; input[i-1]='o'; input[i-2]='d'; }
這個問題是有限狀態機的完美匹配。
這是一個有限狀態機如何完成這項工作的流程圖:
令人驚訝的是,不匹配的情況返回到檢查最新字符是否與“ C”匹配,而不是僅僅打印並獲得一個新字符。 這樣做的原因是,如果我們讀到說ccat
或cacat
, cacat
檢查是否仍匹配(較短的)前綴,在這種情況下為c
。
作為另一個示例,請考慮是否要匹配cocoa
,而我們的輸入是cococoa
。 在第五個字符處,我們讀取c
而不是a
(已經匹配了coco
,但尚未輸出任何東西),因此我們需要輸出co
,然后返回到第二個c
匹配處。
我們人類通常不會手動構建這種狀態機。 我們已經有了一個用於字符串的字符串,可以作為一個庫,也可以內置於POSIX兼容的C庫(Linux,Mac,BSD): 正則表達式匹配 。 如果我們使用基本的POSIX,則regcomp()
將根據我們的規范構建高效的狀態機,然后regexec()
處理其上的輸入數據。
不過,這種特殊情況很容易手動實現。 我們要做的是將第一個狀態(“獲取下一個字符”)放入循環外,執行只要“ char = EOF”不成立就繼續的循環,然后在循環內進行其余操作。 然后,最終的“完成”狀態在循環之后。 用偽代碼 :
ch = Next char
While ch != EOF:
If ch != 'c':
Output ch
ch = Next char
Continue
End If
# The second "Get next char" in the flowchart:
ch = Next char
If ch == EOF:
Output 'c'
Break
Else
If ch != 'a':
Output 'c'
Continue
End If
# The third "Get next char" in the flowchart
ch = Next char
If ch == EOF:
Output 'c'
Output 'a'
Break
Else
If ch != 't':
Output 'c'
Output 'a'
Continue
End If
# 'c' 'a' 't' matched (with ch == 't').
Output 'd'
Output 'o'
Output 'g'
ch = Next char
End While
Done
讀取標准輸入的AC程序,將每次出現的cat
轉換為dog
,區分大小寫,因此可以寫成
#include <stdlib.h>
#include <stdio.h>
void cat_to_dog(FILE *in, FILE *out)
{
int ch;
ch = fgetc(in);
while (ch != EOF) {
if (ch != 'c') {
fputc(ch, out);
ch = fgetc(in);
continue;
}
ch = fgetc(in);
if (ch == EOF) {
fputc('c', out);
break;
} else
if (ch != 'a') {
fputc('c', out);
continue;
}
ch = fgetc(in);
if (ch == EOF) {
fputc('c', out);
fputc('a', out);
break;
} else
if (ch != 't') {
fputc('c', out);
fputc('a', out);
continue;
}
fputc('d', out);
fputc('o', out);
fputc('g', out);
ch = fgetc(in);
}
}
int main(void)
{
cat_to_dog(stdin, stdout);
return EXIT_SUCCESS;
}
有限狀態機的問題在於代碼傾向於只寫 。 要理解代碼,或在任何時間范圍內對其進行驗證或維護,您確實需要定義有限狀態機,以便可以將已實現的代碼與有限狀態機進行比較。
至此,我們終於到達了這個“答案”的重點:正確的文檔。
如果無法修改或修復代碼中的錯誤,那么使用精心設計,極其緊密和高效的代碼來解決問題就毫無價值。 (即使是世界上最好的程序員也會在各種復雜程度上犯錯誤和錯誤。如果有人聲稱自己不這樣做,那就是在撒謊。)
通過在上面的代碼中穿插注釋,我們可以對有限狀態機進行解釋。 那就好了; 注釋應始終說明程序員的意圖 ,一段代碼要完成的目的或任務。 取而代之的是,我們經常寫注釋來告訴代碼做什么,而這沒什么用處,因為我們可以很容易地閱讀代碼以查看代碼的作用。 我們不知道的是代碼是否符合程序員的意圖,或者程序員的意圖是否是對根本問題的有效解決方案!
另一種可能性是包括該圖,也許對動作(橢圓形)和測試(平行四邊形)編號,並在引用該圖的代碼中添加注釋。 這比較容易,但遵循起來卻不那么容易(因為您需要不斷交叉引用代碼和圖表)。
不幸的是,省略文檔部分是很常見的( “我會在有更多時間的時候再去做” ),只是簡單地驗證代碼是否可以正確輸入 。 通常不可能對所有可能的輸入都完全測試代碼(盡管這很簡單),因此發現了許多錯誤。 沒有文檔,人就可以檢查代碼並嘗試評估它在邏輯上是否正確 (即,“流程圖”或它實現的有限狀態機是正確的),以及代碼是否與工作模型匹配或並非如此,只有在實踐中將它們咬傷后才能發現它們。 真討厭
有限狀態機是注釋(和文檔)重要性的主要示例,但實際上它適用於您編寫的所有代碼。 學習在注釋中嘗試描述您的推理(解決方案模型)和意圖(您希望代碼完成的工作),並一開始就寫很多注釋。 以后很難養成這種習慣。 經過數十年的編程,我個人仍然在為此奮斗。 如果以后發現沒有必要發表評論,則只需不到一秒鍾的時間即可將其刪除; 但是如果它解釋了我們人類通常不會注意到的一個關鍵的怪癖或復雜的細節,那么以后可能會節省數小時,數天甚至數周的開發時間。
這也意味着注釋掉未使用的代碼的做法不是很有用,因為實際注釋會很快與編譯器(或解釋器)看到的代碼相去甚遠。 相反,學習為您的源使用版本控制系統。 我推薦git 。 它幾乎適用於所有操作系統(請參見此處 ),並且您可以在計算機上本地使用它,也可以在分布式項目中使用它,以防您想將代碼放在GitHub或類似服務上(甚至進行設置)您自己的git服務器)。 這樣,您就可以使代碼及其注釋保持同步; 並且在修改代碼時,您可以分別描述這些更改的原因(變更集)。 掌握了這些要點之后,您會發現它不是負擔,但實際上可以加快代碼開發速度!
基蘭在回答中提到“您正在檢查尚未讀取的a和t字符” 。 您可以利用argc
和argv
來解決此問題。
這是我使用argc
和argv
程序的版本。 您會注意到,這也阻止了您限制輸入緩沖區(即,沒有input[20]
)。
#include <stdio.h>
int main(int argc, char **argv)
{
int i = 0, j = 0;
for(i=1; i<argc; i++)
{
while(argv[i][j] != '\0')
{
if(argv[i][j] == 'c')
{
if(((argv[i][j+1]) == 'a') && (argv[i][j+2] == 't'))
{
argv[i][j] = 'd';
argv[i][j+1] = 'o';
argv[i][j+2] = 'g';
}
}
printf("%c", argv[i][j]);
j++;
}
j=0;
printf(" ");
}
printf("\n");
return 0;
}
樣本輸入和輸出:
$ ./test my favourite cartoon when i was a kid was catdog
my favourite cartoon when i was a kid was dogdog
$ ./test i used to love cats but now i love dogs
i used to love dogs but now i love dogs
PS:以防萬一您出生太晚或沒有在電視上看過很多動畫片; 這是參考: https : //en.wikipedia.org/wiki/CatDog 。
您正在嘗試訪問input[i]
, input[i + 1]
和input[i + 2]
。
采用 :
while (input[i + 2] && input[i + 2] != '\\n')
在您的情況下:
#include <stdio.h>
int main()
{
int i = 0; // loop counter
int size = 0; // size of array
int input[20];
printf("enter text here\n");
while((input[i] = getchar()) != '\n' && i < 19) // input text to the array
{
/* if(input[i]=='c' && input[i+1]=='a' && input[i+2]=='t') // switching characters
{
input[i]='d'; input[i+1]='o'; input[i+2]='g';
}
*/
i++;
size++;
}
input[i] = 0;//ALWAYS null-terminate arrays.
if (i >= 2);
while (input[i + 2]) {
if (input[i] == 'c' && input[i + 1] == 'a' && input[i + 2] == 't') {
input[i] = 'd';
input[i + 1] = 'o';
input[i + 2] = 'g';
}
}
}
i=0; // reset for next loop
while(i < size) // printing the text out ofthe arry
{
putchar(input[i]);
i++;
}
printf("\n");
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.