【问题标题】:Surround a string with 2 chars in C在C中用2个字符包围一个字符串
【发布时间】:2012-04-23 02:22:00
【问题描述】:

我有一个从文件中读取的字符串数组。 在某些时候,我需要取出一个元素,在 * 之前和 * 之后添加并将其放回同一个数组。

到目前为止,我已经设法在末尾添加了一个星号 strcat。它正在正确打印出来。 现在,我如何在开头添加一个?

//malloc for the array has been done when read from file
char **array;
int arraySize;
for (i=0;i<arraySize;i++){
  if (some_condition){
    //Add * chars
    array[i]=strcat(array[i],"*");
    printf("Element %s was marked",array[i]);
  }
 //prints for example *foo*
 }

对不起,如果这个问题完全是愚蠢的,答案可能很明显。提前感谢您提供任何可能的答案!

UPD:数组malloc函数

void readd(FILE *file){
  size=0; /*local size */
  char line[BUFSIZ]; /* Local array for a single word read */

  while ((fgets(line,sizeof(line),file))!=NULL){
    /* trim newline char */
    if (line[strlen(line)-1]=='\n')
    line[strlen(line)-1] = '\0';

    array=(char**)realloc(array,(size+1)*sizeof(char *));
    array[size++]=strdup(line);
  }
}

【问题讨论】:

  • 您需要更改原始字符串array[i],还是可以将其替换为以* 开头和结尾的新字符串?原始的array[i] 字符串是如何分配的:malloc?作为字符常量?作为堆栈上的字符数组?
  • 向我们展示您是如何分配内存并最初读取字符串的。最有效的答案也会更改该代码。
  • @AdamLiss 最好使用相同的数组。内存分配请看OP。
  • 旁注:每行读取的 realloc 效率不高; prealloc N 个“槽”,当你填满它们时,2N 等等......
  • @ShinTakezou 我选择这种方式是因为输入文件的大小是未知的。所以我需要在读取文件时动态重新分配内存。

标签: c string append strcat


【解决方案1】:

如果原始 array[i] 元素有足够的空间容纳其他字符:

int len = strlen(array[i]);
memmove(array[i] + 1, array[i], len); // memmove() allows overlap btwn src & dest
array[i][0] = '*';
array[i][len+2] = '\0';
array[i][len+1] = '*'

编辑:既然你更新了你的问题,我会更新我的答案。 :-)

首先,请注意,像这样使用realloc() 是很危险的:

array=(char**)realloc(array,(size+1)*sizeof(char *));

如果realloc() 失败,则array 被重新分配给NULL,原始指针丢失,孤立分配给它的内存。这样更安全:

char **tmp = realloc(array,(size+1)*sizeof(char *));
if (tmp == NULL) {
 // Out of memory error
}
array = tmp;

当然,如果您经常这样做,您不妨跟踪当前大小,并一次为另外十万或一千个元素分配空间。


由于单个字符串是用strdup() 分配的,因此您有两个选择:

  • 为每个字符分配额外的 2 个字符,以防您需要添加星号。这并不是不合理的,除非有数百万个字符串,或者系统内存受限。

  • 在添加星号之前重新分配每个字符串,使用上面的 sn-ps 之类的代码。

【讨论】:

  • 感谢您的回复和建议。作为一个初学者,我需要一点时间来理解所有的内存分配/重新分配。但我保证我会考虑你的建议 :) 数组中只有几个单词会被标记,所以我想可以分配额外的 2 个字符。因为只有很少的标记词我认为预先重新分配每个字符串是一个可以接受的解决方案。
  • 是的,指针和内存管理是初学者常见的绊脚石,即使是有经验的程序员有时也会弄错。花时间去了解它们是一项非常值得的投资。
  • 我按照你的建议做了,只做了很少的改动以适应我的程序,它运行完美。非常感谢您的建议! :)
【解决方案2】:

您可以将array[i] 中的每个字符从后面开始复制到右侧(到更高的索引),然后将第一个字符替换为“*”。

这假设您有足够的空间来容纳两个额外的星星。

如果没有,你有两个选择

  • 声明/分配足够大的原始空间(至少大两个)或
  • malloc 一个足够大的区域然后从索引 1 开始复制字符串并将星星放在适当的位置(索引 0 和索引 strlen(array[i])+1。不要忘记将 array[i] 中的指针重新分配给 malloc' d 区域之后。

【讨论】:

    【解决方案3】:

    最简单的方法是使用双 strcat。

    但是,你有没有考虑过这种东西的内存管理?你的字符串是如何保存在内存中的?

    在这一行,你丢失了指向原始字符串的指针:

    array[i]=strcat(array[i],"*");
    

    您是否对原始指针有另一个引用?也许你想先保存,然后重新分配相同长度+2个字符,然后放第一个*,复制字符串,放最后一个*并删除原来的指针。

    【讨论】:

    • strcat 将 ptr 返回到结果“字符串”dest,因此指针不应该丢失。为 realloc +1,虽然耗时,但它使它安全......但我建议用 +2 抢先分配字符串,以便为可能的 double * 保留足够的空间
    • @ShinTakezou 对,感谢您注意到指针没有丢失。我正在考虑重新分配,我想我应该提到潜在的内存管理问题。显然我写得太快了。
    • 做双 strcat 确实很棒。但是 strcat 第二个参数只接受const char * 所以我不能在那里使用我的array[i] ...我想。抱歉,我不太明白你丢失指针是什么意思。
    • @AlexMarch - const char* 表示函数承诺不改变数组中的字符,并不意味着数组内容在函数外也必须不变
    • 好的,知道了。谢谢你的解释!
    猜你喜欢
    • 2014-11-12
    • 1970-01-01
    • 2018-04-23
    • 2011-02-01
    • 1970-01-01
    • 2021-12-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多