C - char * 'отличается уровнем косвенности от' char (*) [200] - PullRequest
0 голосов
/ 28 апреля 2018

Для задания программирования на 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;
}

1 Ответ

0 голосов
/ 28 апреля 2018

Во-первых, не имея доступа к остальной части вашего проекта (я предполагаю, что есть несколько других файлов, содержащих некоторые функции, на которые вы ссылаетесь в своем посте), невозможно узнать, как именно вы создаете код . генератор , ограничивающий предложения синтаксическими проблемами.

Объяснение следующих ошибок из вашего поста приведено как в комментариях ниже, так и в строчных комментариях в коде внизу: enter image description here

Во-первых, в вашем отредактированном разделе я не вижу, что это за функция readCode(), потому что вы ее не включили, но если она не создает память, тогда переменная code не может использоваться.

После объявления char (**tokenized)[LINE_LENGTH_LIMIT]; вы пытаетесь использовать элемент нулевого массива char ** без предварительного создания памяти. В лучшем случае ваша программа аварийно завершит работу во время выполнения, а еще хуже - будет работать. Это называется Не определено или Не указано поведение . (читайте о том, как использовать 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 (например, с помощью 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;
}
...