簡體   English   中英

我的串聯函數mystrcat(char *,char *,char *)有什么問題?

[英]What is wrong in my concatenation function mystrcat(char*, char*, char*)?

我最近接受了采訪並要求編寫mystrcat(*s1, *s2, *s3) ,其中s1s2是源字符串,連接結果由s3給出。 我被告知,不要擔心s3內存分配,並假設s1s2不是空/無效字符串。 所以我寫了下面的蹩腳(粗)程序。 有人告訴我有什么毛病s3或東西可以去錯了s3 你能告訴它它是什么/可能是什么?

void mystrcat(char *s1, char *s2, char *s3)
{
    if (! (s1 || s2 || s3)) return; // one/more pointers are invalid

    // copy string s1 into s3
    while(*s1) {
      *s3 = *s1;
      s1++;
      s3++;
    }

    // concatenate string s2 into s3
    while(*s2) {
      *s3 = *s2;
      s2++;
      s3++;
    }

    *s3 = '\0';
}

你能告訴我這里有什么問題嗎? 做什么會更專業呢?

if (! (s1 || s2 || s3) return; // one/more pointers are invalid

應該

if ((!s1) || (!s2) || (!s3)) return;

兩個可能的點

首先,您被告知輸入和輸出指向有效字符串,因此可以說不需要測試有效性。 如果需要,你應該吵鬧失敗。 更好的是:

 void mystrcat(char *s1, char *s2, char *s3)
    {
        ASSERT( s1 );
        ASSERT( s2 );
        ASSERT( s3 );
        ....

然后你基本上寫了strcat / strcpy,你可以重用它們:

void mystrcat(char *s1, char *s2, char *s3)
{
    strcpy( s3, s1 );
    strcat( s3, s2 );
}

如果我正在采訪你以外的其他任何事情,我會特別指出你指出我指定的mystrcat界面是非常精心設計的,並提供了如何改進它的細節。

這是我的評論

  • s1和s2都應該輸入const char*因為你無意修改它們。
  • 你沒有驗證s3有足夠的分配空間來包含s1和s2的組合長度
  • 當用戶傳入錯誤數據(NULL值)時,您將無聲地失敗。 這並不好,因為呼叫者無法區分成功和失敗的呼叫
  • 驗證s1,s2和s3的方法不為null是不正確的(Igor沒錯)

我希望你在面試中問我或自己回答的問題

  • 我應該如何表達未能復制字符串?
  • 你想要一個精確的strcat克隆還是更現代的一個並且做更好的參數驗證?
  • 我可以使用其他標准str函數來完成答案嗎?

除了之前的答案,還有一件事可能出錯:s3可能指向s1或s2字符串的中間位置。 如果這是一個合法的條件,那么你需要更復雜的實現。

關於你的函數定義有幾個批評,但在問題陳述的約束下你的函數會產生正確的答案。 這在技術上並不錯誤。

我的猜測是問題沒有得到有效溝通,或者訪談員的批評沒有得到有效溝通。 也許澄清這些是測試的一部分,是嗎?

以下是可能投訴的快速摘要......

  • 這條線有邏輯錯誤......

    if(!(s1 || s2 || s3))返回;

...因為它會返回,如果所有都為空,但你可能要返回如果有任何空。 這不會導致失敗,因為問題語句說none都不能為null。

  • 上面提到的同一行無聲地失敗了。 最好返回錯誤代碼,拋出異常或斷言。 無聲故障是不好的做法,但技術上仍然正確,因為在給定問題域的情況下,函數不會失敗。
  • s1和s2可以是const char *類型,以提高可讀性和效率(const有助於某些編譯器優化)。
  • 修改參數變量通常被認為是不好的做法。 另一個可讀性問題。
  • 您可以使用現有函數strcpy和strcat。 另一個可讀性和效率的問題。

一個偉大的程序員應該超越技術的正確性,以提高可讀性,效率和強大的錯誤處理能力,但這些主要是主觀的和情境性的。 無論如何,忽略你的第一個if語句中的錯誤,我認為你的函數讀得很好並完成了工作。 :)

  1. 檢查無效

    if(!(s1 || s2 || s3))返回; //一個/多個指針無效

    它實際上檢查至少一個指針是否不為0,例如至少一個指針有效。 它應該是

    if(!s1 ||!s2 ||!s3)返回;

  2. 你沒有檢查s3是否足夠大,或者你是否在外面寫作(但假設是s3很大的權利? - 但它仍然不適用於真正的世界)

  3. 您無法跳過從s1的末尾復制到s3的null。 你在s3中的0之后附加s2所以它將結束“ s1stringvalueNULLs2stringvalue ”(這里的NULL表示值0或null或實際代碼中的nil,這是為了說明)。 任何期望以null結尾的字符串的C方法只會看到“ s1stringvaluepart ”並且將在null處停止。

這是一個解決方案:

void mystrcat(char *s1, char *s2, char *s3)
{
    if (!s1 || !s2 || !s3) return;

    while (*s3++ = *s1++);
    if (!*(s3-1)) --s3;             // reverse over null in s1
    while (*s3++ = *s2++);

    *s3 = 0;
}

你可以測試它:

#include <iostream>
using namespace std;

int main()
{
    char s1[] = "short";
    char s2[] = "longer";
    char s3[20];

    memset(s3, 0, sizeof(s3));
    mystrcat(0,s2,s3);
    cout << "2: " << s3 << endl;

    memset(s3, 0, sizeof(s3));
    mystrcat(s1,0,s3);
    cout << "3: " << s3 << endl;

    memset(s3, 0, sizeof(s3));
    mystrcat(s1,s2,0);
    cout << "4: " << s3 << endl;

    memset(s3, 0, sizeof(s3));
    mystrcat(s1,s2,s3);
    cout << "1: " << s3 << endl;

}

如果我錯了,請糾正我。 復制s1后,s3的最后一個字符不是'\\ 0'嗎? 那么在某些情況下,s2中的剩余字符永遠無法讀取?

從我的理解

while(*s3++ = *s1++);

將復制字符,直到達到NULL並且'\\ 0'不是NULL,或者它是否被視為? 如果我可以假設s1 =“你好”而s2 =“世界!” 然后在復制s1之后,s3看起來像:Hello \\ 0然后復制“世界!” bit會導致s3看起來像:Hello \\ 0 world!\\ 0

它有意義嗎? 我的理解是否正確?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM