programing

문자열에 붙여넣기

powerit 2023. 9. 15. 21:27
반응형

문자열에 붙여넣기

가능한 한 적은 메모리를 사용하여 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

반응형