문자열에 붙여넣기
가능한 한 적은 메모리를 사용하여 C 문자열에 추가하는 가장 효율적인 방법은 무엇입니까?
큰 디렉터리 트리에 있는 파일의 경로를 재구성하려고 합니다.
여기 제가 전에 했던 일에 대한 아이디어가 있습니다.
char temp[LENGTH], file[LENGTH];
file = some_file_name;
while (some_condition) {
parent_dir = some_calculation_that_yields_name_of_parent_dir;
sprintf(temp, "%s/%s", parent_dir, file);
strcpy(file, temp);
}
근데 이건 좀 투박해 보여요.
어떤 도움이라도 주시면 감사하겠습니다.감사합니다!
동일한 메모리 청크에 복사를 원하는 경우에는 복사를 피할 수 없습니다.할당된 청크가 충분히 크다면 사용할 수 있습니다.memmove
원래의 문자열을 첨자를 붙이고 싶은 길이만큼 이동한 다음 처음에 복사하는 것입니다. 하지만 이것이 덜 "터무니없는" 것은 아닌지 의심됩니다.그러나 원래 청크에 사용 가능한 공간이 충분하므로 추가 메모리를 절약할 수 있습니다.
이와 같은 것:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void prepend(char* s, const char* t);
/* Prepends t into s. Assumes s has enough space allocated
** for the combined string.
*/
void prepend(char* s, const char* t)
{
size_t len = strlen(t);
memmove(s + len, s, strlen(s) + 1);
memcpy(s, t, len);
}
int main()
{
char* s = malloc(100);
strcpy(s, "file");
prepend(s, "dir/");
printf("%s\n", s);
return 0;
}
문자열을 순서대로 저장할 필요가 없고 순서대로만 보인다면 "줄"이라고 하는 것을 사용합니다. (많은 "줄"로 구성되어 있습니다. 참조)
기본적으로 벡터(C항에서 배열)라고 생각합니다.struct { char *begin; char *end };
C++에서는 std::string 기능을 모두 구현합니다.C에서는 모든 strxx() 함수에 대한 대체 함수를 쓰거나 라이브러리를 가져와야 합니다.
줄을 다른 줄에 붙이기 위해 "로프"가 하는 일은 단순히 새로운 줄을 가리키는 새로운 시작, 끝 쌍을 삽입하는 것입니다.임시 포인터일 경우 새 문자열을 복사해야 할 수도 있습니다.또는 할당된 문자열이면 문자열의 소유권을 가져 갈 수도 있습니다.
줄은 큰 줄에 아주 좋습니다.그러나 약 8KB 미만이면 memmove와 memcpy로 처리하는 것이 더 빠릅니다.
sprintf()는 일반적으로 '빠름'이 아닙니다.제 이동을 두 번 보류하는 것을 알고 계시기 때문에 속도를 위해서는 아마 더 좋을 것입니다.
malloc()로 문자열을 할당할 경우 realoc()를 사용하여 문자 배열 크기를 조정하여 새 문자열을 포함할 수 있습니다.
char* p = malloc( size_of_first_string );
...
p = realloc( p, size_of_first_string + size_of_prepended_string + 1 );
memmove( p + size_of_prepended_string, p, size_of_first_string );
memmove( p, prepended_string, size_of_prepended_string );
헷갈리는지도 모르지만, 첨언은 줄을 바꾸어 붙이는 것과 같은 것이라고 생각합니다.따라서 "Hello"를 "World"에 붙이는 대신 "World" 문자열을 "Hello"에 붙일 수 있습니다.
const char world[] = "World";
const char hello[] = "Hello";
// Prepend hello to world:
const unsigned int RESULT_SIZE = sizeof(world) + sizeof(hello) + 2 * sizeof('\0');
char * result = malloc(RESULT_SIZE);
if (result)
{
strcpy(result, hello);
strcat(result, world);
puts("Result of prepending hello to world: ");
puts(result);
puts("\n");
}
또한 실행 시간의 주된 낭비는 문자열의 끝을 찾는 것입니다.문자열을 길이와 함께 저장하면 끝을 더 빨리 계산할 수 있습니다.
이동하면서 이름을 보관하는 디렉토리 트리의 맨 위로 이동한 다음 이름을 한 번에 붙여넣을 수 있습니다.최소한 앞으로 밀고 나가면서 불필요한 복사를 하는 건 아닙니다.
int i = 0;
int j;
char temp*[MAX_DIR_DEPTH], file[LENGTH];
while (some_condition) {
temp[i++] = some_calculation_that_yields_name_of_parent_dir;
}
char *pCurrent = file;
for( j = i-1; j > 0; j-- )
{
strcpy(pCurrent, temp[j]);
pCurrent += strlen(temp[j]);
*pCurrent++ = '\';
}
strcpy(pCurrent, filename);
*pCurrent = 0;
끝부터 끈을 유지할 수 있습니다.이미 maxSize를 알고 계신 것 같으니...
그래서 기본적으로 파일이 처음에 (foo.txt) 였다면.
[] [] [] [] [] [f] [o] [o] [.] [t] [x] [t] [\0]
^
|
lastEmpty
이제 부모 디라를 추가하면 다음과 같이 보입니다.
[] [] [] [a] [/] [f] [o] [o] [.] [t] [x] [t] [\0]
^
|
lastEmpty
따라서 코드는 다음과 같이 보일 것입니다(버그가 있을 수 있지만 아이디어는 알 수 있습니다).
char temp[LENGTH], file[LENGTH];
int lastEmpty = put_at_end(some_file_name, file);
// lastEmpty points to right most empty slot
while (some_condition) {
parent_dir = some_calculation_that_yields_name_of_parent_dir;
int len = strlen(parent_dir);
char *tmp = parent_dir + len -1;
while (lastEmpty > 0) {
file[lastEmpty] = *tmp;
lastEmpty --;
tmp--;
}
}
parent_dir가 작을 것으로 예상할 수 있기 때문에 두 번 검토해도 무방합니다.파일 문자열을 전달하고 싶다면 다음을 사용하면 됩니다.file+lastEmpty+1
.
이 솔루션에는 필요 이상의 복사 기능이 없습니다.따라서 디렉토리 이름 검색에서 복사된 바이트 수를 반환할 수 있거나 상위 dir 문자열 길이를 미리 계산할 수 있으면 이를 최적화할 수 있습니다.
void GetFilename(char *pFile)
{
strcpy(pFile, "someFile");
}
void GetParentDir(char *pDir)
{
strcpy(pDir, "/parentdir");
}
int _tmain(int argc, _TCHAR* argv[])
{
char path[1024];
GetParentDir(path);
int dirSize = strlen(path);
path[dirSize] = '/';
GetFilename(path + dirSize + 1);
printf(path);
return 0;
}
배열의 왼쪽과 오른쪽에 버퍼를 둡니다.인덱스를 두 개 보유해야 하지만 여러 번 해야 한다면(그렇지 않으면 효율성에 문제가 없을 것입니다) 가치가 있습니다.제가 제안하는 두 개의 인덱스는 [s;e], 하나는 포함되고 다른 하나는 포함되지 않습니다.
#define BUFSIZE 256
#define LEFTBUF 20
struct mstring
{
char * string;
unsigned s;
unsigned e;
}
void checkbuf(struct mstring *value, int newstringlen, char leftorright)
{
//have fun here
}
char * concat (struct mstring * value, char * str)
{
checkbuf(value, strlen(value,str), 'r');
int i=0;
while (str[i])
value->string[value->e++]=str[i++];
}
char * set(struct mstring * value, char * str)
{
value->e=LEFTBUF;
value->s=LEFTBUF;
concat( value,str);
}
char * prepend (struct mstring * value, char * str)
{
checkbuf(value, strlen(value,str), 'l');
int i=strlen(value,str)-1;
while (i>=0)
value->string[--value->s]=str[i--];
}
int main()
{
struct mstring * mystring= (struct mstring *) malloc(sizeof(struct mstring) );
mystring->string=(char*)malloc(sizeof(char)*BUFSIZE);
set( mystring,"World");
prepend(mystring,"Hallo")
}
그 다음에는 필 서브스트링을 위한 기능을 준비해야 합니다.
언급URL : https://stackoverflow.com/questions/2328182/prepending-to-a-string
'programing' 카테고리의 다른 글
"docker run -d" 후 도커 컨테이너가 자동으로 중지됩니다. (0) | 2023.09.15 |
---|---|
$($).wtclick', '#id', 함수({}) 대 $('#id'.wtclick', 함수({}) (0) | 2023.09.15 |
size_t 유형의 변수에 대한 교차 플랫폼 형식 문자열? (0) | 2023.09.15 |
비트 조작 모범 사례 (0) | 2023.09.15 |
Android Data Binding이 인수를 onClick 메서드에 전달합니다. (0) | 2023.09.15 |