Please help me with a spellcheck program in C. The majority of the coding are complete (I think...). I'm really stuck because I'm not sure why the program wouldn't compile. Admittedly, I'm still an amateur coder, would you also provide a few suggestions on some of the bad coding habits that I have in the code? Thank you!
Error Message:
1>------ Build started: Project: project7, Configuration: Debug Win32 ------
1>Compiling...
1>project7.c
1>c:\users\x309\documents\visual studio 2008\projects\project7\project7\project7.c(16) : warning C4101: 'dictionaryWord' : unreferenced local variable
1>c:\users\x309\documents\visual studio 2008\projects\project7\project7\project7.c(77) : warning C4029: declared formal parameter list different from definition
1>c:\users\x309\documents\visual studio 2008\projects\project7\project7\project7.c(91) : warning C4013: 'strlen' undefined; assuming extern returning int
1>c:\users\x309\documents\visual studio 2008\projects\project7\project7\project7.c(96) : warning C4013: 'strncmp' undefined; assuming extern returning int
1>c:\users\x309\documents\visual studio 2008\projects\project7\project7\project7.c(101) : warning C4013: 'printf' undefined; assuming extern returning int
1>c:\users\x309\documents\visual studio 2008\projects\project7\project7\project7.c(78) : warning C4101: 'i' : unreferenced local variable
1>Linking...
1>project7.obj : error LNK2019: unresolved external symbol _artLength referenced in function _spellCheck
1>C:\Users\x309\Documents\Visual Studio 2008\Projects\project7\Debug\project7.exe : fatal error LNK1120: 1 unresolved externals
1>Build log was saved at "file://c:\Users\x309\Documents\Visual Studio 2008\Projects\project7\project7\Debug\BuildLog.htm"
1>project7 - 2 error(s), 6 warning(s)
What's required...
There is only one stage on this project, writing the spellCheck routine. The spellCheck function has two parameters. The first parameter (article[]) is a pointer to an array of characters. The contents of this array are an article that you need to spell check. The end of the article is marked with the normal 0 (marking the end of a string). The article includes punctuation, upper and lower case words, numbers, and abbreviations. Your function must print every word in the article that cannot be found in the dictionary. The dictionary is the second parameter to the function (more on this later).
#include <stdio.h>
#include<string.h>
char dictionary[1000000];
char article[100000];
void spellCheck(char[], char[]);
int isLetter(char c);
void removePunc(char article[]);
void toLower( char article[]);
void lowerDictionary( char dictionary[]);
int artLength( char article[]);
void nextArticleWord(char article[], char articleWord[], int artLength, char dictionary[]);
int main(void) {
FILE* dict_file;
FILE* article_file;
int bytes_read;
char* p;
dict_file = fopen("american-english.txt", "r");
if (dict_file == 0) {
printf("unable to open dictionary file \"american-english.txt\"\n");
return -1;
}
article_file = fopen("article.txt", "r");
if (article_file == 0) {
printf("unable to open file \"article.txt\"\n");
return -1;
}
/* read dictionary */
p = dictionary;
p = fgets(p, 100, dict_file);
while (p != 0) {
while (*p != '\0') {
p += 1;
}
p = fgets(p, 100, dict_file);
}
/* read article */
p = article;
bytes_read = fread(p, 1, 1000, article_file);
p += bytes_read;
while (bytes_read != 0) {
bytes_read = fread(p, 1, 1000, article_file);
p += bytes_read;
}
*p = 0;
spellCheck(article, dictionary);
}
int articlePosition =0;
int dictionaryPosition = 0;
void spellCheck(char article[], char dictionary[]) {
char articleWord[50];
char dictionaryWord[50];
int articleLength = artLength(article);
removePunc(article);
toLower(article);
lowerDictionary(dictionary);
nextArticleWord(article, articleWord, articleLength, dictionary);
}
void nextDictionaryWord(char dictionary[], char dictionaryWord[]){
int i;
for(i =0; dictionary[dictionaryPosition] != '\n'; i++){
dictionaryWord[i] = dictionary[dictionaryPosition];
dictionaryPosition++;
}
}
int isLetter(char c){
if ( (c>='a'&&c<='z') || (c>='A'&&c<='Z'))
return 1;
return 0;
}
void removePunc(char article[]){
int i, j=0;
for ( i =0; article[i] != 0; i++){
if (isLetter(article[i])){
article[j] = article[i];
j++;
}
else if (!isLetter(article[i])){
article[j] = ' ';
j++;
}
}
}
void toLower( char article[]){
int i=0;
for( i; article[i] != 0; i++){
if ( article[i] >= 'A' && article[i] <='Z')
article[i] = article[i] + 32;
}
}
void lowerDictionary( char dictionary[]){
int i=0;
for(i; dictionary[i] != 0; i++){
if (dictionary[i] >= 'A' && dictionary[i] <= 'Z'){
dictionary[i] = dictionary[i] + 32;
}
}
}
int articleLength( char article[] ){
int count=0;
while (article[count] != 0)
count++;
return count;
}
void nextArticleWord(char article[], char articleWord[], int articleLength, char dictionaryWord[], char dictionary[]){
int j, i;
check:
while(!isLetter(article[articlePosition])){
if (article[articlePosition] == 0){
return;
}
articlePosition++;
}
for(j=0; article[articlePosition] != ' ' || articlePosition == articleLength; j++){
articleWord[j] = article[articlePosition];
articlePosition++;
}
if (strlen(articleWord)<2){
goto check;
}
articleWord[j+1] = 0;
//dictionary search
while (!strncmp(articleWord, dictionaryWord,strlen(articleWord))){
nextDictionaryWord(dictionary, dictionaryWord);
}
if(strncmp(articleWord, dictionaryWord,strlen(articleWord)))
return;
printf(articleWord);
}
You have made a forward declaration:
int artLength( char article[]);
but your actual implementation is:
int articleLength( char article[]);
Make them identical (change either one of them) and your project will compile.
Not much information to go on - in future you need to post the actual error messages you are getting. However, you definitely need to move your function declarations so they appear in the code before the main() function.
Have you tried going through the compiler errors and understanding what they mean?
From a cursory glance, here's where I think the problem is. The compiler error is:
error LNK2019: unresolved external symbol _artLength referenced in function _spellCheck
Which basically means the compiler is looking for a function called artLength, called from function spellCheck. However, it's not finding it.
It seems like you have a function called articleLength, which may be what you meant to write?
I would definitely advise you, however, to go over all the other output from your compiler and try to understand what it means. A lot of it is basically telling you that the compiler can't find certain functions, which is because you're calling them before you actually write them.
Dan's answer is absolutely fine, but the program still wont compile. In spellCheck function you haven't passed dictionaryWord[50] so it would shows you ("too few arguments passed") error as soon as you correct the error Dan pointed out and try to compile it.
This is for those who are viewing this question and trying to implement the spell checker in C:D
Related
I'm given a task to write a program that checks a piece of code, maximum of 20 lines of code, when the program runs you type in a function name, number of lines of code and type in the codes.
It's meant to search in the code and return if the function name you entered is a Library Function or User Defined Function or No Function if it doesn't find it, the code I've written is below, it doesn't work because I made mistakes and I've been trying to fix it but can't seem to figure it out, and I tried debugging to see where I made mistake, and I figured that in the function SearchRealisation it returns an error that
Run-Time Check Failure #2 - Stack around the variable 'buff' was
corrupted.
This program sample returns Library function instead of user defined function
type the function name: addition
Get count string in code: 9
int addition(int num1, int num2)
{
int result = num1 + num2; //trial
return result;
}
int main()
{
addition(8, 9);
}
Output is Library Function but correct output should be User Defined Function since it was defined in the code
void InputText(int length, char Text[MAX_STRINGS][MAX_COLUMNS])
{
//Repeat by Count String
gets_s(Text[0]);
for (int i = 0; i < length; i++)
gets_s(Text[i]);
//Output a string (starting with � zero and ending with Count String-1)
}
void OutMesseg(int param)
{
//Display one of three messages according to the parameter
if (param == -2)
printf("%s", "user defined function");
else if (param == -1)
printf("%s", "no function");
else
printf("%s", "library function");
}
char* DeleteComentsInString(char Text[MAX_STRINGS], char New[MAX_STRINGS])
{
char* a = strstr(Text, "//");
int len = strlen(Text);
if (a != NULL) len -= strlen(a);
strncpy(New, Text, len);
New[len] = '\0';
return New;
}
bool IsTypeC(char Word[MAX_STRINGS])
{
char ctype[6][MAX_STRINGS] =
{
"int",
"bool",
"char",
"float",
"double",
"void"
};
for (int i = 0; i < 6; i++)
{
if (strstr(Word, ctype[i]) != 0)
return true;
}
return false;
}
int SearchRealisation(int length, char Text[MAX_STRINGS][MAX_COLUMNS], int index_fanc, int& end)
{
int count = 0;
int start = -1;
end = -1;
char buff[MAX_STRINGS];
//Find first {
for (int i = index_fanc + 1; i < length && !count; i++)
{
if (strstr(DeleteComentsInString(Text[i], buff), "{") != NULL)
{
count++;
start = i;
}
}
//find last }
for (int i = start + 1; i < length && count; i++)
{
if (strstr(DeleteComentsInString(Text[i], buff), "{") != NULL)
count++;
else if (strstr(DeleteComentsInString(Text[i], buff), "}") != NULL)
count--;
if (!count)
end = i;
}
if (end == -1)
start = -1;
else
return start;
}
int SearchFunction(int length, char Text[MAX_STRINGS][MAX_COLUMNS], char FunctionName[MAX_COLUMNS], int& end)
{
//bool flag = false;
char commentDel[120];
int in;
for (int i = 0; i < length; ++i)
{
DeleteComentsInString(Text[i], commentDel);
if (strstr(commentDel, FunctionName) != NULL)
{
in = strlen(commentDel) - strlen(strstr(commentDel, FunctionName));
if ((in == 0 || (in != 0 && commentDel[in - 1] == ' ')) && (commentDel[in + strlen(FunctionName)] == ' ' || commentDel[in + strlen(FunctionName)] == '(') && strstr(commentDel, ";") == NULL)
{
return SearchRealisation(length, Text, i, end);
}
}
}
end = -1;
return -1;
}
int SearchResult(int length, char Text[MAX_STRINGS][MAX_COLUMNS], char FunctionName[MAX_COLUMNS])
{
int index;
int end;
int start = SearchFunction(length, Text, FunctionName, end);
if (start == -1)
return -1;
index = SearchFunction(length, Text, FunctionName, end);
if (index < 0)
return -2;
return index;
}
int findFunction(char string[MAX_STRINGS][MAX_COLUMNS], char* functName, int M)
{
return 0;
}
int main()
{
int length = 0;
char Code[MAX_STRINGS][MAX_COLUMNS] = { 0 };
char FunctionName[MAX_COLUMNS];
//char ConstantName[MAX_STRINGS];
printf("type the function name: ");
scanf("%s", &FunctionName);
printf("Get count string in code: ");
scanf("%d", &length);
InputText(length, Code);
printf("\n");
OutMesseg(SearchResult(length, Code, FunctionName));
return 0;
}
Well, you have been given a very difficult task:
There's no way to check this, as functions are resolved by a dynamic process that depends on your filesystem state, which is not available at runtime, after you have already compiled your program.
How do you distinguish a function that is compiled in a separate (but user defined) compilation unit from a system defined function? (e.g. double log(double);) that is defined in a math library? There is no way: the linker gets both from a different place (in the first case it gets it from the place you compiled the separate module, in the system case it gets it from a common library directory that has all the system related functions), but you don't have that information available at runtime).
In order to do this task feasible, you'd at least have the full set of source code files of your program. Preprocess them with the cpp(1) preprocessor (so you bypass all the macro expansion invocations) and then check for all function calls in the source code that are not provided in the full set of sources you have. This is quite similar to what the linker does. After compilation, the compiler leaves an object file with the compiled code, and a symbol table that identifies all the unresolved identifiers, and more important all the provided identifiers from this module. The linker then goes on all your modules trying to solve the unknowns, and for each that it doesn't have a solution in your code, it goes to the library directory to search for it. If it doesn't find it in either one, it fails telling you something is wrong.
In my opinion, you have been given a trap task, as the C language preprocess its input (this is something you should do, as many functions are hidden in the internals of macro bodies), then parse the code (for this, you need to write a C parser, which is no trivial task) to select which identifiers are defined in your code and which aren't. Finally you need to check all the calls you do in the code to divide the set in two groups, calls that are defined (and implemented) in your code, and calls that aren't (implemented, all the calls the compiler needs must be defined with some kind of prototype).
It's my opinion, but you have not a simple task, solvable in a short program (of perhaps one hundred lines) but a huge one.
Thanks a lot to everyone that answered I came up with a way to search the code for function definition and thereby return a value if its defined or not, or not even found, might not be the best solution to the task but works so far
I was working on my game and decided to use eclipse as my compiler. I had to compile it for both platforms: x86 and x64. The trouble started there. There are many dependency files in the system path.
And every time I had to change them in order to change the platform. So, I've created a line to set up my configurations faster and without affect the path itself.
This is the line to add into the path that I've created:
%DRIVE%\mingw\mingw%PLATFORM%\bin;%DRIVE%\Dropbox\Machine\Windows\C\Place\bin\x%PLATFORM%;%DRIVE%\Dropbox\Machine\Windows\C\PLUGIN\x%PLATFORM%\bin;
As you guys can see there are two variables there: %DRIVE% and %PLATFORM%.
I wish to change them with a file that I try to create in c.
Here is the code
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
char *strremove(char *str, const char *sub) {
char *p, *q, *r;
if ((q = r = strstr(str, sub)) != NULL) {
size_t len = strlen(sub);
while ((r = strstr(p = r + len, sub)) != NULL) {
while (p < r)
*q++ = *p++;
}
while ((*q++ = *p++) != '\0')
continue;
}
return str;
}
#ifndef HAVE_SETENV
int setenv(const char * variable,const char * value) {
if(!variable || !value)return(0);
int len = strlen(variable)+1+strlen(value)+1;
char * EnvString = calloc(len,sizeof(char));
sprintf(EnvString, "%s=%s", variable, value);
if (!_putenv(EnvString)) {
return (1);
}
if(EnvString)free(EnvString);
return (0);
}
#endif
void change_platform(int argc,char ** argv) {
char * variable = "PLATFORM",* value = "86";
if(argc > 1){
value = argv[1];
}
if (setenv(variable, value)) {
printf("\n environmental variable successfully written");
printf("\n value of the environmental variable written is %s",
getenv(variable));
} else {
printf("\n error in writing the environmental variable");
}
}
int main(int argc, char ** argv) {
change_platform(argc,argv);
getch();
return 0;
}
My code shows the right result inside the program, but when I go and check the system environment itself, nothing changes. Am I doing something wrong.
Detail: I thought it was because of mingw which isn't native from Windows, then I've created I file in Visual c++ too, but it did not work either.
Please remember it affects only the environment of the current process
getenv, _wgetenv
int main( void )
{
char *libvar;
// Get the value of the LIB environment variable.
libvar = getenv( "LIB" ); // C4996
// Note: getenv is deprecated; consider using getenv_s instead
if( libvar != NULL )
printf( "Original LIB variable is: %s\n", libvar );
// Attempt to change path. Note that this only affects the environment
// variable of the current process. The command processor's
// environment is not changed.
_putenv( "LIB=c:\\mylib;c:\\yourlib" ); // C4996
// Note: _putenv is deprecated; consider using putenv_s instead
// Get new value.
libvar = getenv( "LIB" ); // C4996
if( libvar != NULL )
printf( "New LIB variable is: %s\n", libvar );
}
I keep receiving an error regarding malloc and I'm trying to find out how to get this code to work without using stdlib.h in the header. Just stdio.h, is this possible and how? As I'm totally confused
#include <stdio.h>
void allocate(int* score_array, const int input)
{
int iter;
for(iter = 1;iter <= 11;++iter)
{
if( (input < iter*10) && (input >= (iter-1)*10 ) )
{
++(score_array[iter-1]);
}
}
}
void printf_star(const int len)
{
int iter;
for(iter = 0;iter < len;++iter)
{
printf("*");
}
printf("\n");
}
int main()
{
int iter, size, temp;
int* buffer;
int score_array[11];
for(iter = 0;iter < 11;++iter)
{
score_array[iter] = 0;
}
printf("How many grades will you be entering?\n");
printf("Enter a number between 1 and 100: ");
scanf("%d", &size);
buffer = (int*)malloc(size*sizeof(int));
for(iter = 1;iter <= size;++iter )
{
printf("Getting grade %d. You have %d grade(s) left to enter\n", iter, size-iter+1);
printf("Enter a number between 0 and 100: ");
scanf("%d",&temp);
if( (temp>=0) && (temp <= 100) )
{
buffer[iter-1] = temp;
}
else
{
do
{
printf("Invalid Value!\n");
printf("Getting grade %d. You have %d grade(s) left to enter\n", iter, size-iter+1);
printf("Enter a number between 0 and 100: ");
scanf("%d",&temp);
}
while( (temp < 0) || (temp > 100) );
}
}
for(iter = 1;iter <= size;++iter)
{
allocate(score_array, buffer[iter-1]);
}
for(iter = 0;iter < 11;++iter)
{
printf_star(score_array[iter]);
}
return 0;
}
I keep getting this error:
hw08.c: In function ‘main’:
hw08.c:56: warning: incompatible implicit declaration of built-in function ‘malloc’
This is only a warning, not an actual error, so the program still compiles.
To eliminate the warning you can declare the malloc in your file:
#include <stdio.h>
extern void * malloc(unsigned long);
You could also just include stdlib.h, unless you have a major reason not to.
Header files just define the functions prototypes by using the extern keyword. The actual implementation of malloc resides in libc depending on the OS.
Not defining a function/system call prototype is indeed a warning, not a compile-time error, contrary to what many have conveyed in the comments!
Coming to the actual workaround, if you want to avoid using the #include <stdlib.h>, you either need to use:
#include <malloc.h> (deprecated since c89)
Define the header all by yourself, with extern void * malloc(size_t);
Credits to #Chris Rouffer too! :)
You need to include stdlib.h if you want to access the malloc() function, because that is where it is defined. Otherwise the compiler doesn't know what to do.
You really are supposed to include the header in your code if you want to use the function, however, in theory you could just paste the implementation of malloc() in your source and then use it from there without the header. This is a bad idea however, since anybody looking at the code would expect malloc() to refer to the standard implementation defined in stdlib.h.
Note: Fixed (decription at bottom)
For some reason the following code:
(*p_to_array)[m_p->number_of_match_positions] = (*p_to_temp_array)[k];
where the types are:
match_pos_t (*p_to_array)[];
match_pos_t (*p_to_temp_array)[];
int number_of_match_positions;
int k;
BTW: match_pos_t is a struct:
typedef struct match_pos
{
char* string;
long match_position;
}match_pos_t;
causes a 'syntax error before '(' error'
This error does not occur if this code replaced with other code.
Could someone give me an idea of why this is causing a syntax error, and how I should fix this problem?
Entire relevant code:
typedef struct match_pos
{
char* string;
long match_position;
}match_pos_t;
typedef struct match_positions
{
int number_of_match_positions;
match_pos_t (*match_positions)[];
}match_positions_t;
typedef struct search_terms
{
int number_of_search_terms;
char* search_terms[];
}search_terms_t;
int BMH_string_search(char* search_string, char* file_string, match_positions_t* match_positions)
{
return 0;
}
int determine_match_pos(search_terms_t** s_terms, char* file, match_positions_t* m_p)
{
int i,j,k;
match_positions_t* temp_m_p;
i=0;
/* s_terms is a null terminated data structure */
while((*s_terms+i) != NULL)
{
for(j=0; j<(*s_terms+i)->number_of_search_terms; j++)
{
/* search for the string positions */
BMH_string_search((*s_terms+i)->search_terms[j], file, temp_m_p);
/* load out search positions into the return array */
if(temp_m_p->number_of_match_positions != 0)
{
int total_m_ps = m_p->number_of_match_positions + temp_m_p->number_of_match_positions;
m_p->match_positions = (match_pos_t (*)[])realloc(m_p->match_positions, sizeof(match_pos_t)*total_m_ps);
k = 0;
for( ; m_p->number_of_match_positions<total_m_ps; m_p->number_of_match_positions++)
{
(*(m_p->match_positions))[m_p->number_of_match_positions] = (*(temp_m_p->match_positions))[k];
k++;
}
}
free(temp_m_p);
}
i++;
}
return 0;
}
It appears I have been rather stupid. An extra set of parenthesis around the values being referenced does the trick (question code has been updated with fix):
Original:
(m_p->*match_positions)[m_p->number_of_match_positions] = (temp_m_p->*match_positions)[k];
Fixed:
(*(m_p->match_positions))[m_p->number_of_match_positions] = (*(temp_m_p->match_positions))[k];
If anyone has an explanation, though, about why the first is incorrect, rather than the second, it would be nice to hear though, as I thought that
object->*object2
was the same as
*(object->object2)
Is this correct or is there some c definitions that I am missing out on here?
I thought that object->*object2 was the same as *(object->object2)
No, in C, the . and -> operators expect an identifier as their right operand. The .* and ->* operators don't exist in C, you have to spell out *(structure.member) or *(structure_ptr->member) manually.
The following line has the problem int (*f)(int, int) = (argv[2][0] == 'd') , on compiling it says declaration not allowed here . Should the line be declared at the start , any better way of doing this .Any suggestions would be greatly appreciated?
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int encode(int ch, int key) {
if (islower(ch)) {
ch = (ch-'a' + key) % 26 + 'a';
ch += (ch < 'a') ? 26 : 0;
}
else if (isupper(ch)) {
ch = (ch-'A' + key) % 26 + 'A';
ch += (ch < 'A') ? 26 : 0;
}
return ch;
}
int decode(int ch, int key) {
return encode(ch, -key);
}
int main(int argc, char **argv) {
int ch;
int key;
if (argc < 2) {
printf("USAGE: cipher <integer key> <encode | decode>\n");
printf("Then, just type your text and it will automatically output the en/de crypted text! :)\n");
return 1;
}
key = atoi(argv[1]);
if (key < 1 || key > 25) {
printf("Key is invalid, or out of range. Valid keys are integers 1 through 25.\n");
return 1;
}
int (*f)(int, int) = (argv[2][0] == 'd') ?
decode :
encode;
while (EOF != (ch=getchar()))
putchar(f(ch, key));
return 0;
}
In C (prior to C99), you have to declare variables at the start of a block.
Either compile your code as C99, or change the code so that f is declared at the start of a block.
In c89/90 You must declare all the variables in the starting of the block
But In c99 , You can compile your code with -std=c99 like this:
gcc -Wall -std=c99 test.c -o test.out
Other than the part pointed out by NPE, you can use typedef to create a Function Type. like this:
typedef void FunctionType (int, int); And then use it(as a separate type) to create function pointers.
Makes reading easy.
Should the line be declared at the start
In C89 definitions must occur before any statements in the block. If you do move it, you don't have to move the whole line (and of course you don't want to move the whole line to before the code that checks argv[2] is valid). Just move the definition of f:
int ch;
int key;
int (*f)(int,int);
...
f = (argv[2][0] == 'd') ? decode : encode;
any better way of doing this
It's not necessarily better in this case, but note that the rule is the start of a block, not necessarily the start of a function.
So, you could just write:
{
int (*f)(int, int) = (argv[2][0] == 'd') ?
decode :
encode;
while (EOF != (ch=getchar()))
putchar(f(ch, key));
}
return 0;
You can easily get into arguments about this coding style. Some people think every function should define all its variables up front, and that introducing a block just to define a variable is cluttered and/or confusing. Some people (and especially those who use C++ as well as C) think you should restrict the scope of each variable to as narrow a piece of code as possible, that that defining everything at the start of the function is cluttered and/or confusing. But even they might consider a bare block excessive.