对于C编程任务,我试图编写几个头文件来检查所谓的“X编程语言”的语法。我最近才开始写第一个头文件。这是我写的代码:
#ifndef _DeclarationsChecker_h_
#define _DeclarationsChecker_h_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define LINE_LENGTH_LIMIT 200
#define CODE_LINE_LIMIT 1000
void checkDeclarations(char **code, int num_lines) {
char *currentLine;
for (int currentLineNum = 0; currentLineNum < num_lines; currentLineNum++) {
if (code[currentLineNum] != NULL) {
currentLine = code[currentLineNum];
char (**tokenized)[LINE_LENGTH_LIMIT];
for (int i = 0; i < strlen(currentLine); i++) {
tokenized[i] = strtok(currentLine, " ");
if (tokenized[i] == NULL)
break;
}
char *currentToken;
for (int i = 0; i < LINE_LENGTH_LIMIT; i++) {
currentToken = tokenized[i];
if (strcmp("***", currentToken))
break;
char (*nextToken) = tokenized[i + 1];
if (strcmp("global", currentToken)) {
if (!strcmp("character", nextToken) && !strcmp("integer", nextToken) && !strcmp("double", nextToken) && !strcmp("string", nextToken)) {
printf("Declarations: unknown data type %s at line %d", nextToken, currentLineNum);
}
}
if (strcmp("character", currentToken) || strcmp("integer", currentToken) || strcmp("double", currentToken) || strcmp("string", currentToken)) {
char *functionName = strtok(nextToken, '(');
if (strcmp("character", functionName) || strcmp("integer", functionName) || strcmp("double", functionName) || strcmp("string", functionName) || strcmp("while", functionName) || strcmp("if", functionName) || strcmp("else", functionName) || strcmp("global", functionName) || strcmp("equal", functionName) || strcmp("nequal", functionName) || strcmp("return", functionName)) {
printf("Declarations: naming violation of %s at line %d", functionName, currentLineNum);
}
for (int i = 0; i < strlen(functionName); i++) {
if (!isalnum(functionName[i]) && (functionName[i] != '_') && (functionName[i] != '?')) {
printf("Declarations: naming violation of %s at line %d", functionName, currentLineNum);
}
}
}
}
}
}
}
#endif
我收到了几个编译警告,我会将这些警告添加到末尾,当我尝试启动程序时,它会立即给出一个“程序崩溃”错误,但我认为可能是因为尚未写入头文件。我能做些什么来消除我犯的错误?谢谢你的回答,任何帮助都将不胜感激。(请注意,我是C新手,我没有完全理解数组、指针和双指针之间可交换性的概念(例如:**ptr))
...\declarationschecker.h(30): warning C4018: '<': signed/unsigned mismatch
...\declarationschecker.h(32): warning C4047: '=': 'char (*)[200]' differs in levels of indirection from 'char *'
...\declarationschecker.h(42): warning C4047: '=': 'char *' differs in levels of indirection from 'char (*)[200]'
...\declarationschecker.h(59): warning C4047: 'function': 'const char *' differs in levels of indirection from 'int'
...\declarationschecker.h(59): warning C4024: 'strtok': different types for formal and actual parameter 2
...\declarationschecker.h(66): warning C4018: '<': signed/unsigned mismatch
...\declarationschecker.h(47): warning C4047: 'initializing': 'char *' differs in levels of indirection from 'char (*)[200]'
需要标题的主c文件发布在下面:
#include "CodeReader.h"
#include "BracketsChecker.h"
#include "DeclarationsChecker.h"
#include "StatementsChecker.h"
#include "SSAChecker.h"
int main(int argc, char * argv[]) {
if (argc < 2) {
printf("Please provide X code file name\n");
exit(1);
}
char **code = readCode(argv[1]);
int num_lines = getCodeNumLines();
checkBrackets(code, num_lines);
checkDeclarations(code, num_lines);
checkProgramStatements(code, num_lines);
checkSSA(code, num_lines);
cleanMemory(code);
int terminalHung; scanf("%d", &terminalHung);
return 0;
}
最佳答案
首先,如果不能访问项目的其余部分(我假设还有其他几个文件包含您在文章中引用的一些函数),就不可能知道您究竟是如何创建代码生成器的,从而将建议限制在语法问题上。
下面的注释和底部代码中的行内注释都解释了您文章中的以下错误:
首先,在您编辑的部分中,我看不到函数readCode()
是什么,因为您没有包含它,但是如果它不创建内存,那么变量code
就不能使用。
在声明char (**tokenized)[LINE_LENGTH_LIMIT];
之后,尝试使用char **
的第零数组元素,而不首先创建内存。充其量,你的程序在运行时会崩溃,更糟的是,它看起来会工作。这称为Undefined或Unspecified behavior。(阅读如何使用malloc)。因为您正在为字符串集合准备存储,所以只需要两个维度,而不需要三个维度。achar *[]
或achar **
都可以。在这两种情况下,都必须在使用前初始化并创建内存。但是,由于您已经知道最大行数和最大行长度,所以只需声明并使用:char tokenized[CODE_LINE_LIMIT][LINE_LENGTH_LIMIT];
。
另外,声明char *token = 0;
与strtok一起使用。(原因见评论)
另外,声明一次乘法使用的变量(例如i
)。原因见注释)
对于其余部分,请再次查看内嵌注释,以查看如何在代码中解决以前的错误/警告:
static void checkDeclarations(char **code, int num_lines)
{
char *token = 0;//use with strtok
char *currentLine;
char tokenized[CODE_LINE_LIMIT][LINE_LENGTH_LIMIT] = {{0}};
int i, len; // declare multiply used variables once
for (int currentLineNum = 0; currentLineNum < num_lines; currentLineNum++) {
if (code[currentLineNum] != NULL) {
currentLine = code[currentLineNum];
//char (*tokenized)[LINE_LENGTH_LIMIT] = {0};
len = strlen(currentLine);
for( i = 0; i< len; i++ ) // corrected
//for (int i = 0; i < strlen(currentLine); i++) // don't do string comparison's in a loop
{ // and avoid comparisons of different types
// return of strlen() is an unsigned int
token = strtok(currentLine, " ");
if (token == NULL) break;
else strcpy(tokenized[i], token);
}
char *currentToken;
//for (int i = 0; i < LINE_LENGTH_LIMIT; i++) { // shadow declaration of previously declared variable
for ( i = 0; i < LINE_LENGTH_LIMIT; i++) { // corrected
currentToken = tokenized[i];
if (strcmp("***", currentToken))
break;
char (*nextToken) = tokenized[i + 1];
if (strcmp("global", currentToken)) {
if (!strcmp("character", nextToken) && !strcmp("integer", nextToken) && !strcmp("double", nextToken) && !strcmp("string", nextToken)) {
printf("Declarations: unknown data type %s at line %d", nextToken, currentLineNum);
}
}
if (strcmp("character", currentToken) || strcmp("integer", currentToken) || strcmp("double", currentToken) || strcmp("string", currentToken)) {
//char *functionName = strtok(nextToken, '('); // strtok 2nd argument requires a string, not an integer
char *functionName = strtok(nextToken, "("); // corrected
// note: calling this in a loop will be a problem. either Declare 'functionName' at top of function
// or use 'token', already declared
if (strcmp("character", functionName) || strcmp("integer", functionName) || strcmp("double", functionName) || strcmp("string", functionName) || strcmp("while", functionName) || strcmp("if", functionName) || strcmp("else", functionName) || strcmp("global", functionName) || strcmp("equal", functionName) || strcmp("nequal", functionName) || strcmp("return", functionName)) {
printf("Declarations: naming violation of %s at line %d", functionName, currentLineNum);
}
//for (int i = 0; i < strlen(functionName); i++) { // "i" has already been declared above
for ( i = 0; i < len; i++) { // corrected
if (!isalnum(functionName[i]) && (functionName[i] != '_') && (functionName[i] != '?')) {
printf("Declarations: naming violation of %s at line %d", functionName, currentLineNum);
}
}
}
}
}
}
}
编辑以解决评论中的问题。。。
您可能已经知道以下内容,但您的帖子没有给出任何提示,因此我提供以下内容以防万一:
在将字符串分配给
char *str
之前(例如,通过使用strcpy
或strcat
等),必须创建内存:int desiredStrLen = 80;
char *str = calloc(desiredStrLen + 1, 1);
if(str)// test return of calloc before trusting it worked
{
//use str
...
free(str); // always, when finished with any dynamically allocated memory, free it.
对于字符串集合(例如读取文件行时需要),可以为一组字符串创建内存确定文件中的行数和最长行数后,可以创建足够的内存,将从文件中读取的每一行复制到字符串中:
char **currentLine = Create2DStr(numLines, longestLine);
if(strings)
{
/// use currentLine (in your loop)
...
strcpy(currentLine[i], code[currentLineNum]);
...
// when finished with string collection, free it.
free2DStr(&strings, numLines);
我上面使用的函数可以通过多种方式实现。我使用以下内容:
char ** Create2DStr(ssize_t numStrings, ssize_t maxStrLen)
{
int i;
char **str = {0};
str = calloc(numStrings, sizeof(char *));
for(i=0;i<numStrings; i++)
{
str[i] = calloc(maxStrLen + 1, 1);
}
return str;
}
void free2DStr(char *** str, ssize_t numStrings)
{
int i;
if(!(*str)) return;
for(i=0;i<numStrings; i++)
{
free((*str)[i]);
(*str)[i] = NULL;
}
free((*str));
(*str) = NULL;
}