问题描述
编辑:结果我使用的编译器不支持可变长度数组,所以我无法使用 MSVC 实现我想要的符号
我有一个函数,它接受一个字符串数组和一个查询字符串,并返回数组中与查询匹配的字符串的索引。
int findStringIndex(char query[],int strLength,char* strArray,int numStrings) {
for (int i = 0; i < numStrings; i++) {
for (int j = 0; j < strLength; j++) {
// Skip to next word if there is a mismatch
if (query[j] != *(strArray+ (i * strLength) + j))
break;
if (query[j] == '\0' && *(strArray + (i * strLength) + j) == '\0')
return i;
}
}
return -1;
}
值得注意的是,字符串的长度和数组的大小都不同,因为我在几个不同的地方使用了这个函数,并且字符串的大小不同。目前,这种方法有两个问题:
- 丑陋的数组访问符号
*(strArray+ (i * strLength) + j))
而不是像strArray[i][j]
之类的东西 - 当我调用该函数并将字符串数组作为第三个参数传递时,我收到警告,即我传递的参数从 char* 中“在间接级别上有所不同”
有没有办法告诉编译器接受一个变量作为数组轴之一的大小,以便我可以使用符号 strArray[i][j]
?
另外,我应该如何定义函数,以免收到“间接级别”警告?
编辑:作为澄清,字符串数组没有参差不齐。它们具有恒定大小的维度,但我想在其上使用该函数的不同数组具有不同的大小。代码运行良好并在当前状态下实现了所需的行为,我只是想确保我以正确的方式编写内容
以下是我可能与此函数一起使用的数组的两个示例(不同的字符串大小):
char instructionStrings[NUM_INSTRUCTIONS][INST_MAX_CHARS] = {
"nop","lit","litn","copy","copyl","asni",/* etc */
};
char typestrings[NUM_TYPES][TYPE_MAX_CHARS] = {
"null","int8","int16","int32","int","real32","real"
};
其中 INST_MAX_CHARS 和 TYPE_MAX_CHARS 是不同的值。然后我会为第二个例子调用 findStringIndex(userInput,TYPE_MAX_CHARS,typestrings,NUM_TYPES);
之类的函数
解决方法
如果您的编译器支持可变长度数组,则可以按以下方式声明和定义该函数,如下面的演示程序所示。
#include <stdio.h>
#include <string.h>
size_t findStringIndex( size_t m,size_t n,char a[m][n],const char *s )
{
size_t i = 0;
while ( i < m && !( strcmp( a[i],s ) == 0 ) ) ++i;
return i;
}
int main(void)
{
enum { M1 = 3,N1 = 10 };
char a1[M1][N1] =
{
"Hello","World","Everybody"
};
const char *s = "Hello";
size_t pos = findStringIndex( M1,N1,a1,s );
if ( pos != M1 )
{
printf( "\"%s\" is found at position %zu.\n",s,pos );
}
else
{
printf( "\"%s\" is not found.\n",s );
}
s = "World";
pos = findStringIndex( M1,s );
}
s = "Everybody";
pos = findStringIndex( M1,s );
}
s = "Bye";
pos = findStringIndex( M1,s );
}
return 0;
}
程序输出为
"Hello" is found at position 0.
"World" is found at position 1.
"Everybody" is found at position 2.
"Bye" is not found.
,
-
使用正确的尺寸类型:
size_t
-
您可以通过使用指向数组的指针来使用“普通”索引。
int findStringIndex(char query[],size_t strLength,char (*strArray)[strLength],size_t numStrings) {
for (size_t i = 0; i < numStrings; i++) {
for (size_t j = 0; j < strLength; j++) {
// Skip to next word if there is a mismatch
if (query[j] != strArray[i][j])
break;
/* ..... */
我假设您传递的是二维字符数组(不是指针数组)
,其他答案涵盖了如何使用可变长度数组 (VLA) 获得所需的数组访问语法。
如果您在不支持 VLA 的系统上工作,您可能需要继续使用与您已经展示的接近的实现。
但是,有一些解决方法。
解决方法 1:使所有字符串大小相同
如果您在通常较小的字符串上使用此函数。
,然后不是允许 INST_MAX_CHARS
和 TYPE_MAX_CHARS
是不同的值,而是规定传递给此函数的所有数组必须具有相同的第二维值。因此,在实践中,它将是指令字符串和类型字符串上所有字符串镜头的最大值。 (您可能需要实现自己的 MAX
宏。)
#define X_MAX_CHARS MAX(INST_MAX_CHARS,TYPE_MAX_CHARS)
char instructionStrings[NUM_INSTRUCTIONS][X_MAX_CHARS] = {
"nop","lit","litn","copy","copyl","asni",/* etc */
};
char typeStrings[NUM_TYPES][X_MAX_CHARS] = {
"null","int8","int16","int32","int","real32","real"
};
然后,您的函数可能如下所示:
int findStringIndex(char query[],char (* strArray)[X_MAX_CHARS],int numStrings) {
for (int i = 0; i < numStrings; i++) {
if (strcmp(query,strArray[i]) == 0) return i;
}
return -1;
}
解决方法 2:使用 _Generic
从 C 2011 开始,C 定义了一个类型选择机制调用 _Generic
。 Clang
和 GCC
自引入该功能以来就支持它,最近版本的 MSVC 也是如此。显然,如果您使用的不是至少 Visual Studio 2019 version 16.8 Preview 3,那么您将不会拥有此功能。
使用 _Generic
,您可以检测第二个维度的大小,并调用一个不同的函数来使用它。
#define findStringIndex(Q,A,N) \
_Generic((A),\
const char (*)[INST_MAX_CHARS] : findStringIndex_I(Q,N),\
const char (*)[TYPE_MAX_CHARS] : findStringIndex_T(Q,\
default : -1)
其中,findStringIndex_I
和 findStringIndex_T
分别被定义为处理它们知道如何支持的字符串数组。您可以创建一个宏来自动创建函数,以防您需要添加许多此类函数。
#define DEFINE_FIND_STRING_INDEX(SUFFIX,STRING_SZ) \
int findStringIndex_ ## SUFFIX ( \
char query[],\
char (* strArray)[STRING_SZ],\
int numStrings) { \
for (int i = 0; i < numStrings; i++) { \
if (strcmp(query,strArray[i]) == 0) return i; \
} \
return -1; \
}
DEFINE_FIND_STRING_INDEX(I,INST_MAX_CHARS)
DEFINE_FIND_STRING_INDEX(T,TYPE_MAX_CHARS)
解决方法 3:
虽然不像 _Generic
那样通用,但由于您只处理字符串的大小,因此您可以使用条件表达式完成同样的事情。通过选择所提供数组的第一个元素的大小,这实际上为您提供了第二个维度的大小,您可以确定要调用的适当函数。
#define findStringIndex(Q,N) \
((sizeof((A)[0]) == INST_MAX_CHARS) ? findStringIndex_I(Q,N) : \
((sizeof((A)[0]) == TYPE_MAX_CHARS) ? findStringIndex_T(Q,N) : \
-1))
与 _Generic
一样,要调用的各个函数是单独实现的。