C 在字符串前面加前缀

C 在字符串前面加前缀,c,string,concatenation,C,String,Concatenation,使用尽可能少的内存,在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, fi

使用尽可能少的内存,在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;
}
#包括
#包括
#包括
void prepend(char*s,const char*t);
/*将t前置到s。假设s已分配足够的空间
**对于组合字符串。
*/
无效预结束(字符*s,常量字符*t)
{
尺寸长度=标准长度(t);
memmove(s+len、s、strlen(s)+1);
memcpy(s、t、len);
}
int main()
{
char*s=malloc(100);
strcpy(s,“文件”);
在前面加上“dir/”;
printf(“%s\n”,s);
返回0;
}

您可以维护从末尾开始的字符串。既然你似乎已经知道最大尺寸了

所以基本上如果文件最初是(foo.txt)

现在,如果您添加一个父目录,它将如下所示

[] [] [] [a] [/] [f] [o] [o] [.] [t] [x] [t] [\0]
       ^      
       |      
    lastEmpty           
因此,代码看起来像(可能有bug,但你明白了)


因为我想我们可以期望parent_dir很小,所以再检查两次就可以了。如果要传递文件字符串,只需使用
file+lastpempty+1

此解决方案的复制量不超过所需量。它确实需要一个strlen,因此,如果目录名检索可以返回复制的字节数,或者如果您可以预先计算父目录字符串长度,则可以对其进行优化

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;
}
sprintf()通常不是“快速的”。因为您知道它是预先挂起的memmove(),所以为了提高速度,两次可能会更好

如果你最初用MalCube()分配字符串,你可能会考虑使用RealCube()来调整字符数组,以便它们可以包含新的字符串。

   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 );

您可以爬到目录树的顶部,在前进过程中保留名称,然后一次将所有名称粘贴在一起。至少这样,你就不会因为推到前面而进行不必要的复制了

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;

也许我有点困惑,但我相信前置符和附加交换的字符串是一样的。因此,可以将字符串“World”附加到“Hello”之后,而不是在“Hello”前面加上“Hello”:


此外,执行时间的主要浪费是查找字符串的结尾。如果字符串是按长度存储的,则可以更快地计算末端。

如果您不需要按顺序存储字符串,而只是看起来是按顺序存储的,那么请使用一种称为“绳子”的东西。(它由许多“字符串”组成,请参阅。)

我相信它基本上是一个向量(用C术语,一个数组),由
struct{char*begin;char*end}

在C++中实现了所有的STD::string函数。在C语言中,您需要为所有strxxx()函数编写(或获得一个库)替换函数

“绳子”在将一根绳子预绑到另一根绳子之前所做的只是插入一个指向新绳子的新的开始、结束对。如果是临时指针,它可能还必须复制新的字符串。或者,如果字符串是已分配的字符串,则它可以获得该字符串的所有权


绳子对大绳很有用。但使用memmove和memcpy处理小于8kb的数据要快得多。

我在数组的左侧和右侧留下了一个缓冲区。你必须持有两个索引,但如果你必须持有很多次(否则效率就没有问题了),它就会失效。我建议的两个指数是]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")

  }

然后你必须为填充子字符串准备一个函数

你说的是大尺度,这让我觉得你需要它来加快速度。对你来说,哪一个更重要?快还是小?我想说快/高效肯定更重要。@d03boy:哎呀,忘了那个了。谢谢。可以通过一些计算,得到父目录的名称吗?不仅可以返回父目录,还可以返回父目录的长度吗?(这将在下面发布的一些算法中节省一个strlen,并允许您在最后只进行一次分配。)这是有道理的。您不能使用memcpy而不是for循环吗?prepend()可以通过在s和t上使用C99“restrict”限定符进行更多优化。如果
s
的长度大于
t
,它将被切断。memmove中的第三个参数应该考虑
s
的长度。它应该是:memmove(s+len,s,strlen(s));您想将strlen(s)字节从源复制到目标。@yentup,@brooksbp:更改为移动
strlen(s)+1
字节-尾随的0也必须移动。您的想法是正确的,但在这种情况下效果不太好,因为有两个以上的字符串。我需要迭代地在字符串前加前缀。如果将strcpy和strcat行放在while循环中,那么在第二次迭代中,您必须创建一个新的char数组或移动存储在“result”中的内容,以便有空间进行预处理。如果知道源和目标不重叠,memcpy()通常会快得多。因此,检查realloc返回值并在返回不同指针时使用memcpy可能是值得的。您不需要在
realloc
中+1来说明终止
\0
char?@Geremia是正确的。别忘了在realloc的大小中添加一个。我会编辑它,插入+1我喜欢这个建议。即使最终需要的是一个字符数组,最后也很容易计算绳子的最终长度并分配一个合适大小的缓冲区(并复制一次)。
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;
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");
}
 #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")

  }