大多数时候,我问的问题与我错误做的代码的特定部分有关,或者我忽略了一些错误,但这一次,我不知道从哪里开始。我甚至不知道我想做什么是可能的。
我被赋予了一个编写代码的赋值,该代码获取类似于变量声明的字符串,例如int x,y;
是有效输入。 char c,*cptr,carray[80];
是有效输入的另一个例子。
代码将创建用户输入的内容,并将打印所占用的内存量。
例如,在第一个示例(int x,y;
)中,代码将创建2个整数,而打印" x需要4个字节,y需要4个字节"。
在第二个例子中,代码将创建一个字符,一个指向字符的指针和一个包含80个字符的字符串,并且将打印" c需要1个字节,cptr需要4个字节,carray需要80个字节&# 34;
这甚至可能吗?在代码开始之后声明变量不是有效的代码。必须在C之前宣布它们。所以我没有办法做到这一点......
答案 0 :(得分:1)
这是一个解析问题 - 您需要解析输入字符串并找出它的含义。你不需要实际“创建”任何东西,你只需要弄清楚编译器为该代码创建的变量的大小。
解析实际上是一个非常大的主题,有很多关于它的书和写的工具,以使其更容易。虽然您可以使用antlr或bison之类的工具来完成此任务,但它们可能有点过分 - 一个简单的递归下降手写解析器可能是最好的方法。
类似的东西:
const char *parse_declaration(const char *p) {
/* parse a declaration, printing out the names and sizes of the variables
* 'p' points at the beginning of the string containing the declaration, and the
* function returns the pointer immediately after the end or NULL on failure */
int size;
if (!(p = parse_declspecs(p, &size))) return 0;
do {
const char *name;
int namelen, declsize;
if (!(p = parse_declarator(p, size, &name, &namelen, &declsize))) return 0;
printf("%.*s requires %d bytes\n", namelen, name, declsize);
p += strspn(p, " \t\r\n"); /* skip whitespace */
} while (*p++ == ',');
if (p[-1] != ';') return 0;
return p;
}
const char *parse_declspecs(const char *p, int *size) {
/* parse declaration specifiers (a type), and output the size of that type
* p points at the string to be parsed, and we return the point after the declspec */
p += strspn(p, " \t\r\n");
if (!isalpha(*p)) return 0;
int len = 0;
while (isalnum(p[len])) len++;
if (!strncmp(p, "char", len)) {
*size = sizeof(char);
return p+len; }
if (!strncmp(p, "int", len)) {
*size = sizeof(int);
return p+len; }
... more type tests here ...
if (!strncmp(p, "unsigned", len)) {
p += len;
p += strspn(p, " \t\r\n");
if (!isalpha(*p)) {
*size = sizeof(unsigned);
return p; }
while (isalnum(p[len])) len++;
if (!strncmp(p, "int", len)) {
*size = sizeof(unsigned int);
return p+len; }
... more type tests here ...
}
return 0;
}
const char *parse_declarator(const char *p, int typesize, const char **name, int *namelen, int *declsize) {
/* parse a declarator */
p += strspn(p, " \t\r\n");
while (*p == '*') {
typesize = sizeof(void *); /* assuming all pointers are the same size...*/
p++;
p += strspn(p, " \t\r\n"); }
declsize = typesize;
if (isalpha(*p)) {
*name = p;
while (isalnum(*p) | *p == '_') p++;
*namelen = p - *name;
} else if (*p == '(') {
if (!(p = parse_declarator(p+1, typesize, name, namelen, declsize))) return 0;
p += strspn(p, " \t\r\n");
if (*p++ != ')') return 0;
} else
return 0;
p += strspn(p, " \t\r\n");
while (*p == '[') {
int arraysize, len;
if (sscanf(++p, "%d %n", &arraysize, &len) < 1) return 0;
p += len;
declsize *= arraysize;
if (*p++ != ']') return 0;
p += strspn(p, " \t\r\n"); }
return p;
}
应该让你开始......
答案 1 :(得分:0)
如果您尝试动态执行输入代码,据我所知,如果不存储代码然后再次编译就无法实现。然而,这似乎是一个非常讨厌和冗长的方法。如果您要尝试的只是从输入计算声明的大小,我会做的是接收字符串,调用分析/分解字符串的函数。因此,例如,如果字符串有&#34; int&#34;,&#34; char&#34;等等。我知道会知道我正在处理什么样的声明,并且在我知道我正在处理什么声明之后我可以只计算声明的变量数量,并在你的例子中保留一个计数器,它是x,y。我会在计数器上循环并计算声明类型的大小以及声明的数量。
答案 2 :(得分:0)
当然,这是可能的;这只是一点工作。您将不得不研究C声明语法,然后编写代码来识别它(基本上是一个小的编译器前端)。
例如,在声明中
char c, *cptr, carray[80];
你有一系列令牌:
char c , * cptr , carray [ 80 ] ;
将识别作为类型说明符(char
),后跟三个声明符;直接声明符,指针声明符和数组声明符。
您可以使用malloc
或calloc
动态创建对象的空间。然后,您需要创建某种表来将标识符(变量名称)映射到动态创建的对象。您将无法将这些内容视为常规C代码中的常规变量;你将要进行大量的表查找和解除引用。
答案 3 :(得分:0)
当然,您可以使用一种解析器来完成此操作。假设您不想实际执行您给出的代码,您可以读取该字符串,然后计算每个特定类型的变量被声明的次数,并因此计算内存量。但是,根据教授的要求,您可能会遇到不同的问题。
特别是,每个处理器上不同类型的大小可能会有所不同。除char
外,您需要考虑到这一点。如果您正在分析正在执行程序的计算机的内存要求,这很容易,因为您可以通过const
获得sizeof
个值,以获取大小,但如果没有,你的程序更难,特别是因为你不能假设知道任何变量的大小。
其次,struct
对一些更有趣的C规则会有问题。你需要考虑它们吗?
所以,这是完全可能的,因为与您在问题中所说的相反,您的代码并不需要&#34;创建&#34;一个变量 - 它可以为每种类型创建一个内存总计,并在完成后打印出来。
答案 4 :(得分:0)
想我会发布我的解决方案只是任何人都感兴趣
void* q5(char* str_in)
{
char runner;
int i=0,memory,counter=0,arr_size;
runner=str_in[i];
while(1)
{
if(runner=='i') //the input is integer
{
memory=sizeof(int);
break;
}
if(runner=='c') //input is char
{
memory=sizeof(char);
break;
}
if(runner=='d') //input is double
{
memory=sizeof(double);
break;
}
if(runner=='s') //input is short
{
memory=sizeof(short);
break;
}
if(runner=='l') //input is long
{
memory=sizeof(long);
break;
}
if(runner=='f') //input is float
{
memory=sizeof(float);
break;
}
} //we know the type of data, skip in the string until first variable
while(runner!=' ') //advance until you see empty space, signaling next variable
{
i++;
runner=str_in[i];
}
while(runner==' ') //advance until you encounter first letter of new variable
{
i++;
runner=str_in[i];
} //runner is now first letter of first variable
while(runner!=';') //run on the string until its over
{
if(runner==',') //if its ',', then spaces will occur, skip all of them to first char that isnt space
{
i++;
runner=str_in[i];
while(runner==' ')
{
i++;
runner=str_in[i];
} //runner now points to first letter of variable
continue;
}
if(runner=='*') //current variable is a pointer
{
counter=counter+4; //pointers are always 4 bytes regardless of type!
i++;
runner=str_in[i];
while((runner!=',')&&(runner!=';')) //while runner is still on this variable
{
printf("%c",runner);
i++;
runner=str_in[i];
}
printf(" requires 4 bytes\n"); //now runner is the first character after the variable we just finished
continue;
}
while((runner!=',')&&(runner!=';')) //now is the case that runner is the first letter of a non pointer variable
{
printf("%c",runner);
i++;
runner=str_in[i];
if((runner==',')||(runner==';')) //we are done
{
printf(" requires %d bytes\n",memory);
counter+=memory;
continue;
}
if(runner=='[') //this variable is an array
{
printf("[");
i++;
runner=str_in[i]; //runner is now MSB of size of array
arr_size=0;
while(runner!=']')
{
printf("%c",runner);
arr_size*=10;
arr_size=arr_size+runner-48; //48 is ascii of 0
i++;
runner=str_in[i];
} //arr_size is now whats written in the [ ]
printf("] requires %d bytes\n",arr_size*memory);
counter+=arr_size*memory;
i++;
runner=str_in[i]; // should be ',' since we just finished a variable
continue;
}
}
}
printf("Overall %d bytes needed to allocate\n",counter);
return (malloc(counter));
}