【问题标题】:string reversal in cc中的字符串反转
【发布时间】:2013-03-09 03:30:45
【问题描述】:
#include<stdio.h>
#include<malloc.h>
#include<string.h>
#define SUCCESS 0
#define FAILURE -1
int str_rev(char **s, char **d){
  int count = 0;
  if(s == NULL || d == NULL){
   printf("\n Invalid address received! \n");
   return FAILURE;
  }
  else{
   while(**s != '\0'){
    **s++;count++;
   }
   while(count > 0){
    **d++ = **s--;count--;
   }
   **d = '\0';
   return SUCCESS;
  }
}
int main(){
 int ret_val = SUCCESS;
 char *a = "angus";
 char *b;
 b = malloc((strlen(a) * sizeof(*a)) + 1);
 ret_val = str_rev(&a,&b);
 if(ret_val == FAILURE){
   printf("\n String is not reversed! going to quit! \n");
   free(b);
   return FAILURE;
 }
 printf("\n b:%s \n",b);
 free(b);
 return SUCCESS;
}

我正在编写一个简单的程序,不使用预定义的字符串反转函数。但这给我带来了分段错误。我相信我正在访问正确的内存地址。

已编辑:

#include<stdio.h>
#include<malloc.h>
#include<string.h>
#define SUCCESS 0
#define FAILURE -1
int str_rev(char *s, char **d){
  int count = 0;
  if(s == NULL || d == NULL){
   printf("\n Invalid address received! \n");
   return FAILURE;
  }
  else{
   while(*s != '\0'){
    s++;count++;
   }
   s--;
   while(count > 0){
    printf("\n *s:%c \n",*s);   // prints the values correctly in the reverse order
    *(*d)++ = *s--;count--;
    printf("\n **d:%c \n",*((*d)-1)); // doesnt print the values, after the assignement
   }
   **d = '\0';
   printf("\n s:%s *d:%s \n",s,*d); // both s and d doesnt print the values copied
   return SUCCESS;
  }
}
int main(){
 int ret_val = SUCCESS;
 char *a = "angus";
 char *b,*x;
 b = malloc((strlen(a) * sizeof(*a)) + 1);
 x = b;
 if(b == NULL){
 }
 ret_val = str_rev(a,&b);
 if(ret_val == FAILURE){
   printf("\n String is not reversed! going to quit! \n");
   free(b);
   return FAILURE;
 }
 printf("\n b:%s \n",b);
 free(b);
 return SUCCESS;
}

我修改了上面的代码,因为 'a' 包含字符串。因此,一个指针就足以指向该位置,因为不需要进行任何更改。但即使在上述更改之后,“s”中的内容也不会被复制到“d”。在打印“printf("\n b:%s \n",b);" 后出现段错误.

【问题讨论】:

  • ret 定义在哪里?
  • 哪里是 ;在printf("\n b:%s \n",b)之后?
  • b = malloc(sizeof(b)) 将为char * 分配空间。我想你需要b = malloc(strlen(a)+1)
  • @Angus 了解如何使用编译器显示的警告以及如何调试。所有这些问题都可以通过使用它们来解决。
  • 为了详细说明@Ganesh 的评论,malloc(sizeof(b)) 将分配sizeof(b) 字节(可能是4 或8 字节,具体取决于系统),因为b 是一个指针。显然,这不足以存储长于几个字符的字符串,因此malloc(strlen(a)+1) 是正确的。

标签: c


【解决方案1】:

除了内存分配问题还有你代码中的第二个问题:

第一
在你的复制循环之后:

   while(count > 0){
    **d++ = **s--;count--;
   }

你不会终止 d string ny null

添加

**d= '\0';

第二次:在你的第一个循环之后

   while(**s != '\0'){
    **s++;count++;
   }

您从 Null 复制目标第一个字符变为 '\0' 然后如何使用 %s 进行打印

您应该减少s 以指向最后一个字符而不是空字符。通过--s

第三

内存分配喜欢:

 char *a = "angus";
 char *b;
 b = malloc(strlen(a)*sizeof(*a) + 1);

不要忘记为b 释放()内存

四个
接下来是你忘了从str_rev()返回return SUCCESS;

弗斯

您正在将指针传递给在调用函数中改变b 和's' 值的指针。当您使用&amp;s 调用并修改s 时,没有字符串指向“angus”字符串。

像下面一样,我用单指针代替了你的逻辑。

int str_rev(char *s, char *d){
  int count = 0;
  if(s == NULL || d == NULL){
   printf("\n Invalid address received! \n");
   return FAILURE;
  }
  else{
   while(*s != '\0'){
    s++;
    count++;
   }
   count;
   --s;
   while(count > 0){
    *d = *s;
   // printf("\n %c %c", *d, *s);
    d++ ;
    s--;
    count--;
   } 
   *d = '\0';
  }
  return SUCCESS;
}

在 main 中调用为:

ret_val = str_rev(a, b);

编辑:第二个代码

我注意到您对我对两者都使用单指针的建议不满意!

在你的第二个(编辑)中有一些重复的错误:

(1): 从函数 str_rev() 你又忘记到 return SUCCESS
(2): 你的 str_rcv 函数的语法是 int str_rev(char *s, char **d) ,第一个参数是char*,但在main() 中,您将其称为ret_val = str_rev(&amp;a,&amp;b);,这是错误的不兼容指针分配。你应该这样称呼:

ret_val = str_rev(a, &b); 

(3): 对您很重要:在第二个参数中,您传递 &amp;b 而在 str_rev() 函数中,您正在更新 d 指针,因此更新您分配的 b记忆通过malloc(),你不能那样做!
这也会导致错误memory clobbered before allocated block

您应该更正您的代码以这样调用:(请阅读 cmets

 b = malloc((strlen(a) * sizeof(*a)) + 1);
 if(b == NULL){
   return FAILURE; // added this line too 
 }
 char* x = b;  // first assign b to x, notice x and b are of 
               // same type char*
 ret_val = str_rev(a,&x);  // know pass &x instead of &b 

(4): 虽然我以前的代码也可以工作,但也得到了新版本:

#define SUCCESS 0
#define FAILURE -1
int str_rev(char *s, char **d){
  int count = 0;
  if(s == NULL || d == NULL){
   printf("\n Invalid address received! \n");
   return FAILURE;
  }
  else{
   while(*s != '\0'){
    s++;count++;
   }
   s--;
   while(count > 0){   
    *(*d)++ = *s--;
    printf("\n *s:%c And **d: %c\n",*(s+1), *((*d)-1));  // for bug finding 
                             // because s decremented and d incremented  
     count--;

   }
   **d = '\0';

   return 0;
  }
}

主函数():

int main(){
 int ret_val = SUCCESS;
 char *a = "angus";
 char *b;
 b = malloc((strlen(a) * sizeof(*a)) + 1);
 if(b == NULL){
   return -1;
 }
 char* x = b;
 ret_val = str_rev(a,&x);
 if(ret_val == FAILURE){
   printf("\n String is not reversed! going to quit! \n");
   free(b);
   return FAILURE;
 }
 printf("\n b:%s \n",b);
 free(b);
 return SUCCESS;
}

它的工作输出是:

 *s:s And **d: s

 *s:u And **d: u

 *s:g And **d: g

 *s:n And **d: n

 *s:a And **d: a

 b:sugna 

Here your running code at Codpad

【讨论】:

  • 我已经用你们的 cmets 更正了我的代码,但仍然出现分段错误。
  • @Angus 我知道问题是通过将指针传递给指针,您将 b 更改为指向 null 所以我认为空白打印没有任何意义
  • @Angus 抱歉,但我提到的代码中存在许多错误,我提到的每个错误几乎也更正了您的代码 请找到我更新的代码:它的运行实际参见:Codepad
  • @Angus for the point (3) 您试图修改已分配内存的b。这是不允许的。请同时阅读Memory Clobbering Error 这个示例,您的代码产生的内存破坏-错误的原因相同。
  • @Angus (2) 在将s 复制到d 之后,在表达式*(*d)++ = *s--; 你不应该修改ds 记住-- and ++ 运算符将更改d 指向回到以前的位置,这就是我使用 *(s+1), *((*d)-1) 的原因,并且 NO i++ 不等于 i + 1i++ 等于 i = i + 1 同样*((*d)--) 等于*((*d)-1)!
【解决方案2】:

这里:

**s++

您正在递增 char ** s。这会将其更改为指向下一个在您的程序中没有意义的 char *

由于运算符优先级,**s++(*(*(s++)) 相同。也就是说,它返回由s 指向的char * 指向的char 的值,并且作为副作用递增s 以指向“下一个”char *(其中定义不明确,因为您没有 char *s 的数组。

C 字符串操作中的一个典型习语是*p++,与(*(p++)) 相同。这将返回由p 指向的char 的值,并作为副作用将p 设置为指向下一个char,这将是字符串中的下一个字符。要对char ** 做同样的事情,必须写*(*p)++,或更明确地写(*((*p)++))

另外,不必使用char **s 来反转字符串;只需char *s 即可完成。

【讨论】:

  • 没有朋友注意到你的回答,但我认为你的回答最重要!
  • @GrijeshChauhan 我不同意。 Samuel 的回答确定了在您确定的未定义行为之前发生的未定义行为。它们都是未定义的行为,因此它们同样重要。
  • Samuel:也许最好明确说明**s++ 中的s++** 之前进行评估。
  • @modifiablelvalue,在这种情况下,我不喜欢“之前评估过”这个短语,但我将扩展运算符优先级;谢谢。
  • @GrijeshChauhan,就我个人而言,我认为我的回答中几乎所有其他人都缺乏的最重要的部分是,安格斯在仅使用指针的情况下使用指向指针的指针让自己变得困难。足够,更优雅。
【解决方案3】:

在这一行

b = malloc(sizeof(b));

sizeof(b) 只是指针的大小,不足以容纳整个字符串。

要么传递你想要 malloc 的大小

b = malloc(42);
b = malloc(strlen(a) + 1);

或者将b改为数组而不是指针

char b[42];

除此之外,我强烈建议学习使用 gdb 或 valgrind 等工具来调试这些分段错误。至少他们会告诉你哪条线路出现了段错误,这将有很大帮助。

【讨论】:

  • malloc(sizeof(42)) 无效——你不能取非变量的大小。 malloc(42) 就是你的意思。
  • @MattPatenaude:哎呀。这就是我复制粘贴所得到的:)
  • 更改后仍然出现 seg_fault
  • @MattPatenaude,有点迂腐,您可以将sizeof 设为一个类型(例如sizeof(unsigned long))。此外,sizeof(42) 在 gcc 中工作(它返回我期望的 int 的大小)虽然我不确定这是否是扩展。
  • @MattPatenaude 这来自 C11 标准: sizeof 运算符产生其操作数的大小(以字节为单位),它可以是表达式或类型的括号名称。大小由操作数的类型决定。结果是一个整数。如果操作数的类型是变长数组类型,则计算操作数;否则,不计算操作数,结果为整数常量。
【解决方案4】:

ret = str_rev(&amp;a,&amp;b); 更改为ret_val = str_rev(&amp;a,&amp;b);

【讨论】:

    【解决方案5】:

    请找到如下重做的函数

    int str_rev(char **sinp, char **dout){
        int count = 0;
        char *s = *sinp; // Dereference the starting address of source
        char *d = *dout; // Dereference the starting address of destination
    
        if(s == NULL || d == NULL){
            printf("\n Invalid address received! \n");
            return FAILURE;
        }
        else{
            while(*s != '\0'){
                *s++;count++;
            }
            s--; // Requires a decrement as it is pointing to NULL
    
            while(count > 0){
                 *d++ = *s--;
                 count--;
            }
        }
        *d = '\0'; // Need a NULL terminator to convert it to string
        return SUCCESS; // Requires a return as all branches of function should return values
    }
    

    【讨论】:

      【解决方案6】:
      char str[] = "hello";
      char *foo = foo;
      

      *foo++ 等效于 *(foo++),而不是 (*foo)++foo++ 导致 foo 指向下一个 char

      char str[] = "hello";
      char *foo = str;
      char **bar = &foo;
      

      **bar++ 等价于**(bar++);,而不是(**bar)++bar++ 导致 bar 指向下一个 char *... 你发现问题了吗?

      (*bar)++ 导致 foo 指向下一个 char。考虑一下你会对ret_val = str_rev(&amp;a,&amp;b);(*s)++;(*d)++ 中调用者的a 和b 变量做些什么。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-02-07
        • 1970-01-01
        • 1970-01-01
        • 2010-10-21
        • 2015-05-24
        相关资源
        最近更新 更多