C 从字符串中删除字符并在删除时动态调整其大小的算法
我正在编写一个算法,从动态大小的数组中删除所有引号,并在删除时减少其长度。以下是我目前的代码:C 从字符串中删除字符并在删除时动态调整其大小的算法,c,algorithm,C,Algorithm,我正在编写一个算法,从动态大小的数组中删除所有引号,并在删除时减少其长度。以下是我目前的代码: void remove_quotations(char *str) { int len = strlen(str); for (int i = 0; i < len; i++) { if (str[i] == '\'') { for (int j = i; j < len - 1; j++) { st
void remove_quotations(char *str)
{
int len = strlen(str);
for (int i = 0; i < len; i++) {
if (str[i] == '\'') {
for (int j = i; j < len - 1; j++) {
str[j] = str[j + 1];
}
len--;
str = realloc(str, len);
}
}
}
输入示例:“1357”、“名称”、“主题”、“2”
预期输出:1357,名称,主题,2
我得到的:1357,名字,主题,2
正如您所看到的,引号按预期移动到了末尾,但是字符串并没有像应该的那样缩短
注意:我不是故意做任何错误检查。当您向上移动字符串时,必须在新字符串的末尾添加0:
for (int j = i; j < len - 1; j++) {
str[j] = str[j + 1];
}
str = realloc(str, len);
if (str) {
str[j] = 0; //String ends with 0, so force 0 at the end of string.
}
关键是,您必须在字符串末尾插入0字符来手动关闭字符串。当您向上移动字符串时,必须在新字符串的末尾添加0:
for (int j = i; j < len - 1; j++) {
str[j] = str[j + 1];
}
str = realloc(str, len);
if (str) {
str[j] = 0; //String ends with 0, so force 0 at the end of string.
}
关键是您必须通过在末尾插入0字符来手动关闭字符串
正如您所看到的,引号按预期移动到了末尾,但是字符串并没有像应该的那样缩短
好的,缩短的是分配给你的绳子的区域,这就是realloc做的。您忘记了缩短实际字符串:字符串的结尾总是有一个\0字节
因此,当您使用printf或put输出此字符串时,程序会导致未定义的行为-这些函数将一直读取,直到找到\0终止符为止,并且它不在realloc之后您可以合法访问的区域内
事实上,这似乎是完全偶然的:realloc没有给你一个新的地址,旧的内容仍然存在
代码中还有另一个错误:如果realloc给您一个不同的地址,它将无法工作,因为调用代码无法收回指针
旁注:
使用realloc时,将结果分配给临时变量。如果返回NULL,则必须释放原始变量
在循环之后,您只需要调用一次realloc
作为参考,固定和注释版本:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *remove_quotations(char *str)
{
// always use the correct type, strlen returns size_t:
// (int would only be a problem here for **huge** strings, still it's better
// getting used to ALWAYS use size_t for sizes.)
size_t len = strlen(str);
for (size_t i = 0; i < len; ++i)
{
if (str[i] == '\'')
{
// move following bytes *including* the final 0 terminator:
memmove(str+i, str+i+1, len-i);
--len;
}
}
// include space for 0 terminator when shortening:
char *tmp = realloc(str, len+1);
if (!tmp)
{
free(str);
return 0;
}
return tmp;
}
int main(void)
{
char test[] = "'1357', 'name', 'topic', '2'";
char *foo = malloc(strlen(test)+1);
strcpy(foo, test);
foo = remove_quotations(foo);
if (foo)
{
puts(foo);
free(foo);
}
return 0;
}
正如您所看到的,引号按预期移动到了末尾,但是字符串并没有像应该的那样缩短
好的,缩短的是分配给你的绳子的区域,这就是realloc做的。您忘记了缩短实际字符串:字符串的结尾总是有一个\0字节
因此,当您使用printf或put输出此字符串时,程序会导致未定义的行为-这些函数将一直读取,直到找到\0终止符为止,并且它不在realloc之后您可以合法访问的区域内
事实上,这似乎是完全偶然的:realloc没有给你一个新的地址,旧的内容仍然存在
代码中还有另一个错误:如果realloc给您一个不同的地址,它将无法工作,因为调用代码无法收回指针
旁注:
使用realloc时,将结果分配给临时变量。如果返回NULL,则必须释放原始变量
在循环之后,您只需要调用一次realloc
作为参考,固定和注释版本:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *remove_quotations(char *str)
{
// always use the correct type, strlen returns size_t:
// (int would only be a problem here for **huge** strings, still it's better
// getting used to ALWAYS use size_t for sizes.)
size_t len = strlen(str);
for (size_t i = 0; i < len; ++i)
{
if (str[i] == '\'')
{
// move following bytes *including* the final 0 terminator:
memmove(str+i, str+i+1, len-i);
--len;
}
}
// include space for 0 terminator when shortening:
char *tmp = realloc(str, len+1);
if (!tmp)
{
free(str);
return 0;
}
return tmp;
}
int main(void)
{
char test[] = "'1357', 'name', 'topic', '2'";
char *foo = malloc(strlen(test)+1);
strcpy(foo, test);
foo = remove_quotations(foo);
if (foo)
{
puts(foo);
free(foo);
}
return 0;
}
您最后需要放置“\0” 下线, str[j]='\0' 以前
len-您需要在最后放置'\0' 下线, str[j]='\0' 以前
len-我假设您使用类似的方法来检查字符串的内容:
printf("%s\n", str);
因此,问题是printf将输出它在内存中找到的所有字符,直到它到达一个终止\0字符
我会像这样更新您的函数:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *remove_quotations(const char *str)
{
size_t len = strlen(str);
char *dst = malloc(len+1);
const char *r = str;
char *w = dst;
while (*r)
{
if (*r == '\'') --len;
else *w++ = *r;
++r;
}
*w = 0;
char *tmp = realloc(dst, len+1);
if (!tmp)
{
free(dst);
return 0;
}
return tmp;
}
int main(void)
{
const char *test = "'1357', 'name', 'topic', '2'";
char *foo = remove_quotations(test);
if (foo)
{
puts(foo);
free(foo);
}
return 0;
}
char* remove_quotations(char *str)
{
int len = strlen(str);
char *str_temp;
for (int i = 0; i < len; i++) {
if (str[i] == '\'') {
/* go until len so that you shift the '\0' one position to the left */
for (int j = i; j < len; j++) {
str[j] = str[j + 1];
}
len--;
/* no need to call realloc here every time */
}
}
str_temp = realloc(str, len + 1);
if (!str_temp) {
printf("Memory allocation error!\n");
free(str);
return NULL;
}
return str_tmp;
}
我假设您使用类似这样的方法来检查字符串的内容:
printf("%s\n", str);
因此,问题是printf将输出它在内存中找到的所有字符,直到它到达一个终止\0字符
我会像这样更新您的函数:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *remove_quotations(const char *str)
{
size_t len = strlen(str);
char *dst = malloc(len+1);
const char *r = str;
char *w = dst;
while (*r)
{
if (*r == '\'') --len;
else *w++ = *r;
++r;
}
*w = 0;
char *tmp = realloc(dst, len+1);
if (!tmp)
{
free(dst);
return 0;
}
return tmp;
}
int main(void)
{
const char *test = "'1357', 'name', 'topic', '2'";
char *foo = remove_quotations(test);
if (foo)
{
puts(foo);
free(foo);
}
return 0;
}
char* remove_quotations(char *str)
{
int len = strlen(str);
char *str_temp;
for (int i = 0; i < len; i++) {
if (str[i] == '\'') {
/* go until len so that you shift the '\0' one position to the left */
for (int j = i; j < len; j++) {
str[j] = str[j + 1];
}
len--;
/* no need to call realloc here every time */
}
}
str_temp = realloc(str, len + 1);
if (!str_temp) {
printf("Memory allocation error!\n");
free(str);
return NULL;
}
return str_tmp;
}
你所做的事情太复杂了。应保存源和目标索引,并将每个符号复制到目标:
void remove_quotations(char *str)
{
int j = 0;
for (int i = 0; str[i]; i++) {
if (str[i] != '\'') {
str[j++] = str[i];
}
}
str[j] = 0;
}
这就是你所要做的
工作示例:您正在做的事情太复杂了。应保存源和目标索引,并将每个符号复制到目标:
void remove_quotations(char *str)
{
int j = 0;
for (int i = 0; str[i]; i++) {
if (str[i] != '\'') {
str[j++] = str[i];
}
}
str[j] = 0;
}
这就是你所要做的
工作示例:您进行了哪些调试?您是否在调试器中运行了程序,或者做了其他任何尝试来查找问题?是的,我的预期输出来自调试。这是测试,而不是调试。调试意味着在代码运行时单步检查代码。如果您已经调试过,那么您将能够准确地告诉我们哪里/什么时候开始出错。@PoVa您可以通过使用链表来提高效率。首先,将字符存储到LL的节点中,遍历LL并在旁边删除带有“in it note”的节点。此处删除只需1次。最后从LL中形成一个字符数组。全面的
复杂性。虽然不相关,但在评论中回答了您的一个问题。@JohnZwinck-the-realloc不仅效率低下,而且是错误的。str是调用指针的本地副本,因此更改其值不会更改原始指针的值。您进行了哪些调试?您是否在调试器中运行了程序,或者做了其他任何尝试来查找问题?是的,我的预期输出来自调试。这是测试,而不是调试。调试意味着在代码运行时单步检查代码。如果您已经调试过,那么您将能够准确地告诉我们哪里/什么时候开始出错。@PoVa您可以通过使用链表来提高效率。首先,将字符存储到LL的节点中,遍历LL并在旁边删除带有“in it note”的节点。此处删除只需1次。最后从LL中形成一个字符数组。总体复杂性取决于。虽然不相关,但在评论中回答了您的一个问题。@JohnZwinck-the-realloc不仅效率低下,而且是错误的。str是调用指针的本地副本,因此更改其值不会更改原始指针的值。realloc调用是错误的,它会使调用指针无效,而不会更改它。它只更改本地副本字符串。realloc参数应为len+1。@Gurang VYAS他的循环没有在末尾添加“\0”。是的,@mch是正确的。我只是想指出他在这次活动中的主要问题。我将更新realloc调用以使其正确。realloc调用错误,它会使调用指针无效,而不会更改它。它只更改本地副本字符串。realloc参数应为len+1。@Gurang VYAS他的循环没有在末尾添加“\0”。是的,@mch是正确的。我只是想指出他在这次活动中的主要问题。我将更新realloc调用以使其正确。据我所知,您的版本也会因为memmove而修改主字符串。我一直在寻找一个不需要的解决方案。@PoVa但这正是您的原始代码所尝试的,在适当的位置执行此操作!复制时剥离字符的版本实际上看起来更简单。抱歉,我把事情弄混了:据我所知,您的版本也会修改主字符串,因为memmove。我一直在寻找一个不需要的解决方案。@PoVa但这正是您的原始代码所尝试的,在适当的位置执行此操作!复制时剥离字符的版本实际上看起来更简单一些。对不起,我把事情搞混了:Dlooks很好,可能需要更多的解释,我建议在这里也使用size\u t,谁知道字符串可以有多长;仍然+1看起来不错,也许有更多的解释,我建议在这里也使用size\u t,谁知道字符串可以有多长;仍然+1