从C中的字符串中删除所有非字母字符 - 可能的编译器问题

时间:2015-09-25 07:27:19

标签: c alphabet string.h

我在C中编写一个函数,它将获取一个字符串并删除所有不是小写字母字符的字符。我到目前为止编写了这段代码:

 protected void btnDelete_Click(object sender, EventArgs e)
 {
     foreach (GridViewRow gvrow in gvDetails.Rows)
     {
         //Finiding checkbox control in gridview for particular row
         CheckBox chkdelete = (CheckBox)gvrow.FindControl("chkSelect");
         //Condition to check checkbox selected or not
         if (chkdelete.Checked)
         {
             //Getting UserId of particular row using datakey value
             int usrid = Convert.ToInt32(gvDetails.DataKeys[gvrow.RowIndex].Value);

             using (SqlConnection con = new SqlConnection("Data Source=murugan-pc;Initial Catalog=rg_lava_software;User ID=sa;Password=123"))
             {
                 con.Open();
                 SqlCommand cmd = new SqlCommand("delete from emp where empid=" + usrid, con);
                 cmd.ExecuteNonQuery();
                 con.Close();
             }
         }
     }
     BindUserDetails();
 }
 }

当我传递字符串" hello [] [] world"该函数似乎主要起作用,除了输出是:

void strclean(char* str) {
   while (*str) {
      if (!(*str >= 'a' && *str <= 'z')) {
         strcpy(str, str + 1);
         str--;
      }
      str++;
   }
}

当我在输入if语句的每一行之后打印它时,这是我收到的输出:

hellowoldd

它似乎非常接近,但我无法理解为什么它会产生这个输出!最奇怪的部分是我已经将代码提供给其他两个朋友,它在他们的计算机上工作正常。我们都在运行相同版本的Linux(ubuntu 14.04.3),并且都使用gcc进行编译。

我不确定代码是否存在导致输出不一致的问题,或者是否是编译问题造成的问题。也许它与我们的机器上的strcpy有关吗?

2 个答案:

答案 0 :(得分:9)

如果范围重叠,strcpy函数不能保证正常工作,就像你的情况一样。来自C11 7.24.2.3 The strcpy function /2(我的重点):

  

strcpy函数将s2指向的字符串(包括终止空字符)复制到s1指向的数组中。 如果在重叠的对象之间进行复制,则行为未定义。

根据memmove,您可以使用C11 7.24.2.2 The memmove function /2之类的内容,其中 使用重叠范围:

  

memmove函数将n指向的对象中的s2个字符复制到s1指向的对象中。 复制的过程就好像n指向的对象中的s2字符首次被复制到n个字符的临时数组中,这些字符与指向的对象不重叠至s1s2,然后将临时数组中的n字符复制到s1指向的对象中。 < / p>

但是,在时间复杂度方面,O(n)而不是O(n2)是一个更好的解决方案,同时仍然是重叠安全的:

void strclean (char* src) {
    // Run two pointers in parallel.

    char *dst = src;

    // Process every source character.

    while (*src) {
        // Only copy (and update destination pointer) if suitable.
        // Update source pointer always.

        if (islower(*src)) *dst++ = *src;
        src++;
    }

    // Finalise destination string.

    *dst = '\0';
}

您会注意到我还使用islower()(来自ctype.h)来检测小写字母字符。由于C标准没有强制要求字母字符具有连续的代码点(数字是唯一保证连续的数字),因此这更具可移植性。

也没有单独检查isalpha()的需要,因为根据C11 7.4.1.2 The isalpha function /2islower() == true暗示isalpha() == true

  

isalpha函数测试isupperislower为真的任何字符,或者......

答案 1 :(得分:4)

来自N1256 7.21.2.3 strcpy函数

  

如果在对象之间进行复制   重叠,行为未定义。

即使区域重叠,也可以使用

memmove

void strclean(char* str) {
   while (*str) {
      if (!islower(*str)) { /* include ctype.h to use islower function */
         memmove(str, str + 1, strlen(str)); /* strlen(str + 1) + 1 (for terminating null character) should be strlen(str) */
      } else {
         str++;
      }
   }
}

由于它从指针中减去未定义的行为以使其指向数组之前的区域,因此我还重构了str操作。< / p>