문제

또한보십시오 C 토크나이저


다음은 제가 작성한 C에 대한 빠른 substr()입니다(예, 변수 초기화를 함수 등의 시작으로 이동해야 하지만 아이디어를 얻으실 수 있습니다).

나는 간단한 한 번의 라이너로 strncpy()를 호출하는 substr()의 "스마트" 구현을 많이 보았습니다!

모두 틀렸습니다(strncpy는 null 종료를 보장하지 않으므로 호출이 올바른 하위 문자열을 생성하지 않을 수 있습니다!)

여기에 더 좋은 것이 있을까요?

버그를 꺼내세요!

char* substr(const char* text, int nStartingPos, int nRun)
{
    char* emptyString = strdup(""); /* C'mon! This cannot fail */

    if(text == NULL) return emptyString;

    int textLen = strlen(text);

    --nStartingPos;

    if((nStartingPos < 0) || (nRun <= 0) || (textLen == 0) || (textLen < nStartingPos)) return emptyString;

    char* returnString = (char *)calloc((1 + nRun), sizeof(char));

    if(returnString == NULL) return emptyString;

    strncat(returnString, (nStartingPos + text), nRun);

    /* We do not need emptyString anymore from this point onwards */

    free(emptyString);
    emptyString = NULL;

    return returnString;
}


int main()
{
    const char *text = "-2--4--6-7-8-9-10-11-";

    char *p = substr(text, -1, 2);
    printf("[*]'%s' (\")\n",  ((p == NULL) ? "<NULL>" : p));
    free(p);

    p = substr(text, 1, 2);
    printf("[*]'%s' (-2)\n", ((p == NULL) ? "<NULL>" : p));
    free(p);

    p = substr(text, 3, 2);
    printf("[*]'%s' (--)\n", ((p == NULL) ? "<NULL>" : p));
    free(p);

    p = substr(text, 16, 2);
    printf("[*]'%s' (10)\n", ((p == NULL) ? "<NULL>" : p));
    free(p);

    p = substr(text, 16, 20);
    printf("[*]'%s' (10-11-)\n", ((p == NULL) ? "<NULL>" : p));
    free(p);

    p = substr(text, 100, 2);
    printf("[*]'%s' (\")\n", ((p == NULL) ? "<NULL>" : p));
    free(p);

    p = substr(text, 1, 0);
    printf("[*]'%s' (\")\n", ((p == NULL) ? "<NULL>" : p));
    free(p);

    return 0;
}

출력 :

[*]'' (")
[*]'-2' (-2)
[*]'--' (--)
[*]'10' (10)
[*]'10-11-' (10-11-)
[*]'' (")
[*]'' (")
도움이 되었습니까?

해결책

돌아오라고 할게요 NULL 입력이 유효하지 않은 경우 malloc()ed 빈 문자열.그렇게 하면 함수가 실패했는지 여부를 테스트할 수 있습니다. if(p) 오히려 if(*p == 0).

또한 귀하의 기능에서 메모리가 누출되는 것 같습니다. emptyString 오직 free()d 하나의 조건부로.당신은 당신을 확인해야합니다 free() 무조건, 즉.바로 직전에 return.

귀하의 의견에 대해서는 strncpy() 다음을 사용하는 경우 문자열을 NUL로 종료하지 않습니다(사실입니다). calloc() 대신 문자열을 할당하려면 malloc(), 복사한 것보다 1바이트 더 많이 할당해도 문제가 되지 않습니다. calloc() 자동으로 모든 값(이 경우 끝 포함)을 0으로 설정합니다.

더 많은 메모를 드리고 싶지만 CamelCase 코드를 읽는 것은 싫습니다.문제가 있는 것은 아닙니다.

편집하다:업데이트와 관련하여:

C 표준에서는 다음을 정의합니다. sizeof(char) 시스템에 관계없이 1이 됩니다.1바이트에 9비트를 사용하는 컴퓨터를 사용하는 경우(금지) sizeof(char) 여전히 1이 될 것입니다.말하는 것이 틀린 것은 아니다. sizeof(char) - 의도를 명확하게 보여주고 호출에 대칭성을 제공합니다. calloc() 또는 malloc() 다른 유형의 경우.하지만 sizeof(int) 실제로 유용합니다(int16비트와 32비트 컴퓨터, 그리고 최신형 64비트 컴퓨터에서는 크기가 다를 수 있습니다.더 많이 알수록.

나는 또한 대부분의 다른 C 코드와의 일관성이 NULL 오류가 아닌 "".나는 많은 기능을 알고 있습니다(예: strcmp()) NULL을 전달하면 아마도 나쁜 일을 할 것입니다. 이는 예상된 것입니다.그러나 C 표준 라이브러리(및 기타 많은 C API)는 "다음을 확인하는 것은 호출자의 책임입니다. NULL, 그렇지 않은 경우 그/그녀를 아기로 만드는 기능의 책임이 아닙니다." 다른 방식으로 하고 싶다면 그것도 좋지만 C 인터페이스 디자인의 강력한 추세 중 하나에 어긋나는 것입니다.

또한, 나는 strncpy() (또는 memcpy())보다는 strncat().사용 strncat() (그리고 strcat())는 의도를 모호하게 합니다. - 코드를 보는 사람이 문자열 끝에 추가하고 싶다고 생각하게 만듭니다. calloc(), 끝이 시작입니다), 원하는 것은 문자열을 설정하는 것입니다. strncat() 마치 문자열에 추가하는 것처럼 보이게 만드는 반면, strcpy() (또는 다른 복사 루틴)을 사용하면 의도한 것과 더 비슷하게 보일 수 있습니다.다음 세 줄은 모두 이 맥락에서 동일한 작업을 수행합니다. 가장 보기 좋다고 생각되는 줄을 선택하세요.

strncat(returnString, text + nStartingPos, nRun);

strncpy(returnString, text + nStartingPos, nRun);

memcpy(returnString, text + nStartingPos, nRun);

을 더한, strncpy() 그리고 memcpy() 아마도 (약간) 조금 더 빠르거나 더 효율적일 것입니다. strncat().

text + nStartingPos 와 같다 nStartingPos + text - 나는 넣을 것이다 char * 첫째, 내 생각에는 그것이 더 명확하다고 생각하지만, 어떤 순서로 넣을지는 당신에게 달려 있습니다.또한, 그 주위의 괄호는 불필요합니다(하지만 좋습니다). + 보다 우선순위가 높습니다. ,.

편집 2:세 줄의 코드는 동일한 작업을 수행하지 않지만 이 컨텍스트에서는 모두 동일한 결과를 생성합니다.저를 잡아주셔서 감사합니다.

다른 팁

간단한 작업이어야 하는 기능에 비해 귀하의 기능은 매우 복잡해 보입니다.몇 가지 문제는 다음과 같습니다(모두 버그는 아닙니다).

  • strdup(), 및 기타 메모리 할당 기능, ~할 수 있다 실패하면 가능한 모든 문제를 허용해야 합니다.
  • 필요한 경우에만 리소스(이 경우 메모리)를 할당하세요.
  • 오류와 유효한 문자열을 구별할 수 있어야 합니다.현재로서는 알 수 없습니다. malloc() 실패 substr ("xxx",1,1) 아니면 일하는 substr ("xxx",1,0) 빈 문자열을 생성합니다.
  • 당신은 그럴 필요가 없습니다 calloc() 어쨌든 덮어쓰게 될 메모리입니다.
  • 모든 유효하지 않은 매개변수는 오류를 일으키거나 유효한 매개변수로 강제 변환되어야 합니다. 그리고 API는 어느 것을 문서화해야 합니다.
  • 해제한 후에 로컬 빈 문자열을 NULL로 설정할 필요가 없습니다. 함수 반환 시 손실됩니다.
  • 당신은 우리에게 필요하지 않습니다 strncat() - 너 ~해야 한다 복사를 하기 전에 사용 가능한 크기와 메모리를 파악하여 (아마도) 더 빠르게 사용할 수 있습니다. memcpy().
  • 문자열 오프셋에 base-0이 아닌 base-1을 사용하면 C의 그레인에 어긋납니다.

다음 세그먼트는 내가 할 작업입니다. 문자열의 끝에서부터 계산하는 음수 값의 Python 관용어를 선호하지만 끝 위치 대신 길이를 유지했습니다.

char *substr (const char *inpStr, int startPos, int strLen) {
    /* Cannot do anything with NULL. */

    if (inpStr == NULL) return NULL;

    /* All negative positions to go from end, and cannot
       start before start of string, force to start. */

    if (startPos < 0)
        startPos = strlen (inpStr) + startPos;
    if (startPos < 0)
        startPos = 0;

    /* Force negative lengths to zero and cannot
       start after end of string, force to end. */

    if (strLen < 0)
        strLen = 0;
    if (startPos >strlen (inpStr))
        startPos = strlen (inpStr);

    /* Adjust length if source string too short. */

    if (strLen > strlen (&inpStr[startPos]))
        strLen = strlen (&inpStr[startPos]);

    /* Get long enough string from heap, return NULL if no go. */

    if ((buff = malloc (strLen + 1)) == NULL)
        return NULL;

    /* Transfer string section and return it. */

    memcpy (buff, &(inpStr[startPos]), strLen);
    buff[strLen] = '\0';

    return buff;
}
char* emptyString = strdup(""); /* C'mon! This cannot fail? */

null인지 확인해야 합니다.널 문자에 대해 여전히 1바이트를 할당해야 한다는 점을 기억하십시오.

strdup이 실패할 수 있습니다(IMHO는 매우 가능성이 낮고 확인할 가치가 없지만).그러나 또 다른 문제가 있습니다. 표준 C 함수가 아닙니다.malloc을 사용하는 것이 더 좋습니다.

memmove 함수를 사용하여 시작부터 길이까지 하위 문자열을 반환할 수도 있습니다.paxdiablo 솔루션의 다른 솔루션 개선/추가:

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>

    char *splitstr(char *idata, int start, int slen) {
            char ret[150];
            if(slen == NULL) {
                    slen=strlen(idata)-start;
            }
            memmove (ret,idata+start,slen);
            return ret;
    }

    /*
    Usage:
            char ostr[]="Hello World!";
            char *ores=splitstr(ostr, 0, 5);
            Outputs:
                    Hello
    */

도움이 되길 바랍니다.TCC C 컴파일러를 사용하여 Windows 7 Home Premium에서 테스트되었습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top