C - 字符 *' differs in levels of indirection from ' 字符 (*)[200]

标签 c arrays pointers header-files double-pointer

对于 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;
}

最佳答案

首先,如果无法访问项目的其余部分(我假设还有其他几个文件包含您在帖子中引用的一些函数),则无法知道您是如何创建代码的生成器,将建议限制在句法问题上。

您帖子中的以下错误的解释在下面的评论和底部代码中的内联评论中: enter image description here

首先,在您编辑的部分中,我看不到函数 readCode() 是什么,因为您没有包含它,但如果它不创建内存,那么变量 code 不能使用。

在声明 char (**tokenized)[LINE_LENGTH_LIMIT]; 之后,您尝试使用 char ** 的第零个数组元素而不先创建内存。充其量,您的程序会在运行时崩溃,更糟糕的是,它似乎可以正常工作。这称为 Undefined Unspecified behavior 。 (阅读如何使用 malloc )。因为您正在为字符串集合准备存储,所以您只需要两个维度,而不是三个。 char *[]char ** 都可以。在任何一种情况下,这些都必须在使用前初始化并创建内存。但是,由于您已经知道最大行数和最大行长度,只需声明并使用: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 之前(例如,通过使用 strcpystrcat 等),您必须创建内存:

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;
}

关于C - 字符 *' differs in levels of indirection from ' 字符 (*)[200],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50077501/

相关文章:

javascript - 从javascript中的数组中删除单击的项目

java - 二维冒泡排序java程序,数组中有字符串和整数

从 CSV 数据构建 C 数组

c - 如何在数组中使用指针而不是括号

c - 节点本身定义的节点指针是如何工作的?

ios - 如何在 LLDB 调试器中打印 C 变量?

javascript - 如何格式化具有大量值的javascript数组

c++ - map中operator[]插入的指针类型的值是否总是NULL?

c - 在 C 中释放一个结构数组

c++ - 通过指针制作字符串