0

我需要做的是当给定一个文本或字符串时

\0abc\n\0Def\n\0Heel\n\0Jijer\n\tlkjer

我需要使用 qsort 并基于 rot 编码比较对这个字符串进行排序。

int my_rot_conv(int c) {
  if ('a' <= tolower(c) && tolower(c) <= 'z')
    return tolower(c)+13 <= 'z' ? c+13 : c-13;
  return c;
}

int my_rot_comparison(const void *a, const void *b) {
  char* ia = (char*) a;
  char* ib = (char*) b;
  int i=0;
  ia++, ib++;
  while (i<strlen(ia)) {
    if (ia[i] == '\0' || ia[i] == '\n' || ia[i] == '\t' || ib[i] == '\0' || ib[i] == '\n' || ib[i] == '\t') {
      i++;
    }
    if (my_rot_conv(ia[i]) > my_rot_conv(ib[i])) {
      return 1;
    } else if (my_rot_conv(ia[i]) < my_rot_conv(ib[i]))
      return -1;
  }
  return 0;
}

我要比较两个以 \0 开头的字符串,在下面的示例中得到 -1。

printf("%d \n", my_rot_comparison("\0Abbsdf\n", "\0Csdf\n"));

但这不适用于带有 qsort 的字符串,因为ia++, ib++;它仅适用于一个单词比较。

char *my_arr;
my_arr = malloc(sizeof(\0abc\n\0Def\n\0Heel\n\0Jijer\n\tlkjer));
strcpy(my_arr, \0abc\n\0Def\n\0Heel\n\0Jijer\n\tlkjer);
qsort(my_arr, sizeof(my_arr), sizeof(char), my_rot_comparison);

并且数组应该像\0Def\n\0Heel\n\0Jijer\n\0\n\tlkjer

我的问题是如何定义适用于包含\0and\t\n字符的字符串的比较函数?

4

3 回答 3

3

strlen根本无法在嵌入\0字节的字符串上正确操作,因为根据函数的定义, strlen将字符串的结尾视为字符串\0开头或之后的第一个遇到的字节。

其余标准 C 字符串函数的定义方式相同。

这意味着您必须使用一组不同的函数来操作可以包含\0字节的字符串(类似)数据。您可能必须自己编写这些函数。

请注意,您可能必须定义一个其中包含length成员的结构,因为您将无法依赖特定的标记字节(例如\0)来标记字符串的结尾。例如:

typedef struct {
    unsigned int length;
    char bytes[];
}
MyString;

如果在您的输入字符串中禁止使用其他字节(除了\0),那么(根据评论者@Sinn)您可以交换它和\0,然后使用普通的 C 字符串函数。但是,尚不清楚这是否适合您。

于 2013-10-31T00:33:43.167 回答
0

假设您在最后使用额外\0的终止

int strlenzz(char*s)
{
  int length =0;
  while(!(*s==0 && *(s+1) == 0))
  {
   s++;
   length++;
  }
  return length+1
} 
于 2013-10-31T00:46:29.310 回答
0

就个人而言,我更喜欢danfuzz的建议,但为了列出替代方案......

您可以使用转义约定,将函数写入:

  • “转义” / 编码,扩展嵌入(但不是终止)'\0'/NUL 说 '\' 和 '0' (采用编写 C 源代码字符串文字时使用的约定),以及
  • 另一个逃避。

这样你仍然可以将它们作为 C 字符串传递,上面的 qsort/rot 比较代码将按原样工作,但你应该非常清楚,strlen(escaped_value)它将返回转义表示中的字节数,这不等于当该值嵌入 NUL 时,未转义值中的字节数。

例如,类似:

void unescape(char* p)
{
    char* escaped_p = p;
    for ( ; *escaped_p; ++escaped_p)
    {
        if (*escaped_p == '\\')
            if (*++escaped_p == '0')
            {
               *p++ = '\0';
               continue;
            }
        *p++ = *escaped_p;
    }
    *escaped_p = '\0'; // terminate
}

转义比较棘手,因为您需要一些方法来确保缓冲区中有足够的内存,或者分配一个新的缓冲区 - 将 unescaped_value * 2 + 1 长度的逻辑大小作为易于计算的最坏情况大小,或者通过计算需要转义的 NUL 并将其大小严格调整为逻辑大小 + #NULs + 1....

于 2013-10-31T01:29:36.430 回答