我正在尝试编写泛型函数来获取整数或字符串数组中的最小元素。我正在使用记忆功能。以下是我写的代码:
编辑:修改代码 - 我从int size_t
更改了int size/* Write a function that returns minimum values of an array of integers or strings */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void returnMinAddress(void *a, void *b, int arr_size, int size) {
b = a;
for (int i = 0; i < arr_size; i++) {
if (memcmp(b, a+((i)*size), size) < 0) {
memmove(b, a+((i)*size), size);
}
}
}
int main() {
void *b = malloc(sizeof(int));
/* For an array of type integer */
int a[8] = {3, 2, 1, -4, 6, 9, 8, -1};
returnMinAddress(a, b, 8, sizeof(int));
printf("The result is : %d\n", *(int *)b);
free(b);
return 0;
}
花了很多时间之后,我无法理解为什么我一直把答案定为0 ..以下是输出的截图。我在这里缺少什么?
原始代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void returnMinAddress(void *a, void *b, int arr_size, int size_t) {
b = a;
for (int i = 0; i < arr_size; i++) {
if (memcmp(b, a+((i)*size_t), size_t) < 0) {
memmove(b, a+((i)*size_t), size_t);
}
}
}
int main() {
void *b = malloc(sizeof(int));
/* For an array of type integer */
int a[8] = {3, 2, 1, -4, 6, 9, 8, -1};
returnMinAddress(a, b, 8, sizeof(int));
printf("The result is : %d\n", *(int *)b);
free(b);
return 0;
}
答案 0 :(得分:5)
您的通用功能无效。
首先,虽然size_t
不是关键字,但它是一个类型说明符。因此,将此单词用作标识符是一个坏主意。
本声明
b = a;
应替换为
memmove( b, a, size_t );
其次根据C标准,您可能不会将指针算法应用于void *
类型的指针,因为类型void
是不完整类型。所以你应该写例如
( char * )a + i * size_t
而不是
a+((i)*size_t)
当函数搜索最小值,然后搜索此语句中的条件
if (memcmp(b, a+((i)*size_t), size_t) < 0) {
应该写成
if ( memcmp( ( char * )a + i * size_t, b, size_t ) < 0)
考虑到所有这些因素可能看起来像
void returnMinAddress( void *a, void *b, size_t n, size_t m)
{
memmove(b, a, m);
for (size_t i = 1; i < n; i++)
{
if ( memcmp( ( char * )a + i * m, b, m ) < 0 )
{
memmove(b, ( char * )a + i * m, m );
}
}
}
但是还有一个问题是该功能无法解决。被认为是原始字节序列的负整数可能大于正数。因此,如果您将尝试上面显示的数组函数
int a[8] = { 3, 2, 1, -4, 6, 9, 8, -1 };
您将得到最小值等于1
,而实际上它等于-4
。
编写这种通用函数的方法之一是以下
#include <stdio.h>
void * returnMinAddress( const void *a, size_t n, size_t m, int cmp( const void *, const void *) )
{
const void *min = a;
for (size_t i = 1; i < n; i++)
{
if ( cmp( ( const char * )a + i * m, min ) < 0 )
{
min = (const char *)a + i * m;
}
}
return (void *)min;
}
int cmp_int(const void *p1, const void *p2)
{
int a = *(const int *)p1;
int b = *(const int *)p2;
return (b < a) - (a < b);
}
int main( void )
{
int a[8] = { 3, 2, 1, -4, 6, 9, 8, -1 };
int *b = returnMinAddress(a, 8, sizeof(int), cmp_int);
printf("The result is : %d\n", *b);
}
程序输出
The result is : -4
答案 1 :(得分:2)
@Vlad from Moscow很好地涵盖了OP代码中的麻烦。
为泛型函数提供需要匹配类型和功能的4个参数的替代方法是使用ProgressBar
。自C11起可用。 ref
_Generic
// needs 4 arguments.
// returnMinAddress(a, b, 8, sizeof(int));
// printf("The result is : %d\n", *(int *)b);
允许代码使用与所需类型匹配的函数
只需要2个参数:指向第一个元素和元素计数的指针。
_Generic
输出
int *min_address_int(int *a, size_t count) {
if (count == 0) {
return NULL;
}
int *min = a;
for (size_t i = 1; i < count; i++) {
if (a[i] < *min) {
min = &a[i];
}
}
return min;
}
char *min_address_char(char *a, size_t count) {
if (count == 0) {
return NULL;
}
char *min = a;
for (size_t i = 1; i < count; i++) {
if (a[i] < *min) {
min = &a[i];
}
}
return min;
}
#define min_address(a, sz) (_Generic((a)+0, \
char *: min_address_char((a)+0, (sz)), \
int * : min_address_int ((a)+0, (sz)) \
))
int main(void) {
int i[] = {3, 2, 1, -4, 6, 9, 8, -1};
printf("Min int %d\n", *min_address(i, sizeof i/sizeof i[0]));
char c[] = {'H', 'e', 'l', 'l', 'o', '!'};
printf("Min char %c\n", *min_address(c, sizeof c/sizeof c[0]));
return 0;
}
答案 2 :(得分:0)
主要问题是这一行:
b = a;
执行此操作后,无论何时循环执行:
memmove(b, a+((i)*size_t), size_t);
它覆盖输入数组的第一个元素,而不是复制到调用者的b
变量中。最简单的解决方法是将其替换为:
memmove(b, a, size_t);
但相反,我建议使用指针变量指向当前的最小元素。在循环结束时,从该指针复制到调用者的内存。
void returnMinAddress(void *a, void *b, int arr_size, int size_t) {
void *min = a;
for (int i = 1; i < arr_size; i++) { // start from 1 because min points to element 0
if (memcmp(min, a+((i)*size_t), size_t) < 0) {
min = a+((i)*size_t);
}
}
memmove(b, min, size_t);
}
此外,对void*
指针使用算术是GNU扩展。您应该将它们转换为char*
以符合标准C.并且使用标准typedef size_t
作为变量是糟糕的风格。