문제
또한보십시오 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)
실제로 유용합니다(int
16비트와 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에서 테스트되었습니다.