【问题标题】:C: Check if array includes consecutive elements that are equalC:检查数组是否包含相等的连续元素
【发布时间】:2018-04-22 15:42:44
【问题描述】:

昨天我有一个 C 测试,但我无法弄清楚最后一个问题:

我们得到了两个数组,其中包含两种类型的数组:包括连续元素相等的数组(例如:{"stack","heap","heap"})和没有连续元素相等的数组(例如: {1,2,3,4,5,6,7,8,9})。

然后我们被要求找到一个函数,如果给定的数组是否包含双精度数,则该函数返回 1 或 0。所以这个函数必须同时处理整数数组和 char * 数组。

这是我今天想出的(但它总是给出错误的答案,然后在比较字符串时崩溃或出现分段错误)

编辑:正确的代码(感谢@BLUEPIXY!)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int contains_dup(void *array, size_t size, size_t sizeoftype, int (*cmp)(const void*, const void*)){
    //array != NULL, size != 0
    char *obj = array;
    size_t i;
    for(i = 0; i < size-1; ++i){
        if(cmp(obj + sizeoftype * i, obj + sizeoftype * (i+1)))
            return 1;
    }

    return 0;
}

int eqi(const void *a, const void *b){
    int x = *(const int *)a;
    int y = *(const int *)b;
    return x == y;
}
int eqs(const void *a, const void *b){
    return strcmp(a, b) == 0;
}

#define TEST(name, cmp)\
do{\
    int test;\
    puts(#name ":");\
    test = contains_dup(name, sizeof(name)/sizeof(*name), sizeof(*name), cmp);\
    test ? puts("doubles? Yes\n") : puts("doubles? No\n");\
}while(0)\
/**/

int main(void){
int ints_yes[] = {0,1,2,2,2,3,4,4,5};
int ints_no[]  = {0,1,2,3,4,5,6,7,8};
char *strings_yes[]={"heap","stack","stack","overflow"};
char *strings_no[] ={"heap","stack","heap","stack","overflow"};

puts("test:");
TEST(ints_yes, eqi);
TEST(ints_no, eqi);
TEST(strings_yes, eqs);
TEST(strings_no, eqs);
return 0;
}

错误的旧代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int array_contains_doubles(void ** array, int size, int sizeoftype){
 int i;
 char **out =(char**) malloc(size * sizeof(char*));

 for(i=0;i<size;i++){            //trying to convert the array of ints to an 
    out[i] = array+i*sizeoftype; //array of char * eg: {1,2} ->{"1","2"}
//  *out[i] +='a';
    printf("%c\n",*out[i]);

 }
 out[i]= NULL;

 while(*(out+1)!=NULL){ 
    if(strcmp(*out,*(out++))==0){ //<- where i get the segmentation error
            return 1;
    }

 }

 return 0;

 }


int main(void){
  int i;
  int ints_yes[] = {0,1,2,2,2,3,4,4,5};
  int ints_no[]={0,1,2,3,4,5,6,7,8};
  char * strings_yes[]={"heap","stack","stack","overflow"};
  char * strings_no[]={"heap","stack","heap","stack","overflow"};

  int test = array_contains_doubles((void **) ints_no, 
  sizeof(ints_no)/sizeof(ints_no[0]), sizeof(int));

  (test) ? (printf("doubles? Yes")) : (printf("doubles? No"));

}

抱歉有任何拼写错误,英语不是我的母语。

【问题讨论】:

  • 您将数组与指针混淆了。 array_contains_doubles 需要一个指向 void * 的指针,但 ints_no 会自动转换为 &amp;ints_no[0],它是指向 int 的指针。 (void **) 演员隐藏了错误。
  • ints_no 不是双指针。
  • 我建议将array_contains_doubles 更改为使用void * 参数而不是void ** 参数,因为void * 可以指向任何对象,而不管其类型如何。
  • 要比较两个对象,您需要知道它们的类型并执行适合类型的比较。单个函数可以为多种不同类型执行此操作的唯一方法是,如果您向它传递一个参数,允许它确定要执行哪种比较。标准的qsort() 函数就是这种事情的典型例子——注意它的一个参数是如何指向一个适合类型的比较函数的指针。
  • 不是if(strcmp(*out,*(out++))==0) UB吗?我认为您应该将其替换为 if(strcmp(*out,*(out+1))==0)

标签: c arrays type-conversion c-strings void-pointers


【解决方案1】:

你的老师很可能会为你实现一个类似于传递给bsearch的函数指针的“仿函数”(研究这个函数)。类似这样的东西:

typedef int comp_func_t (const void*, const void*);

bool equal (const void* obj1, const void* obj2, comp_func_t* comp)
{
  return comp(obj1, obj2)==0;
}

您从应用程序中调用equal,并使用指向要比较的对象的指针,无论它们是什么类型的对象。函数指针指定应该如何比较这种类型的对象。然后为每种类型实现比较函数:

int comp_int (const void* obj1, const void* obj2)
{
  int a = *(const int*)obj1;
  int b = *(const int*)obj2;

  if(a < b)
  {
    return -1;
  }
  else if(a > b)
  {
    return 1;
  }
  else // a == b
  {
    return 0;
  }
}

int comp_str (const void* obj1, const void* obj2)
{
  ...
}

典型用途可能是:

int x;
int y;
...
if(equal(&x, &y, comp_int))
{
  ...
}

现在这只比较两个对象,所以你必须将它扩展为一个数组,1) 对数组进行排序,2) 为排序后的数组中的每两个相邻项目调用它,以确定是否有任何相等。

以上是在 C 中实现类型特定行为的旧的“事实上的标准”方式。在新版本的语言中,可以通过 _Generic 关键字获得更优雅的方式,但这可能不会得到解决在初级班上。

【讨论】:

  • 谢谢,我认为它是这样的,但最后我不敢写一个单独的函数,因为只使用一个函数指定的问题(我可能误解了,事后看来他们可能只是意味着我们不能写两个函数“int check_array_of_ints”和“int check_array_of_strings”)。
  • 在这种情况下,数组应该不排序,因为问题是检查连续重复,而不是任何重复。
猜你喜欢
  • 2018-06-15
  • 2016-10-13
  • 1970-01-01
  • 2017-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-13
  • 1970-01-01
相关资源
最近更新 更多