Unknown Error with Conversion [C] - c

For some reason when building my program, it says that I have this error:
error: invalid conversion from 'char' to 'const char*' [-fpermissive]
strcpy(phrase[counter].word, ch);
I'm not really sure what the compiler means, I've tried changing char ch to const char ch, but that doesn't seem to fix the issue. If anyone could shed some light on this issue that would be great.
Here is the code you can refer to:
const char* clean_word(void);
void create_word(struct Word_setup phrase[], FILE *fp)
{
char ch;
fscanf(fp, "%s", &ch);
strcpy(phrase[counter].word, ch);
strcpy(phrase[counter].word, clean_word());
}
const char* clean_word()
{
int i;
const char *ch = phrase[counter].word;
ch = phrase[counter].word;
for (i = 0; i < M; i++)
{
if (phrase[counter].word[i] == 39 || isalpha(phrase[counter].word[i])) //39 is the ASCII value for: '
i = i; //Just to be there, no reason to it. I just want the program to do nothing if its a letter or '
else
phrase[counter].word[i] = '\0';
}
return ch;
}
Also in case you're wondering what this is for, I'm building a program that will scan a *.txt file and then print out the word with the highest number of appearances, as as well as the number of appearances.
If you've already read my old post, I decided to try writing it without re-allocating space every time the array gets filled, and I just set it to 200 max different types of words. I will change the program once I'm finished so that it reallocates space every time that the array fills up.

The problem is here:
char ch;
fscanf(fp, "%s", &ch);
strcpy(phrase[counter].word, ch);
The strcpy() function expects its second argument to be a pointer to the head of the source string, but ch is a char, not a char * or const char *. As Keith Thompson explained, this is an error because integers are not implicitly convertible to pointers in C (other than a constant expression with value 0). Even if the compiler performed an implicit conversion anyway, the behavior would surely not be what you want.
Moreover, the fscanf() isn't going to do what you want, either, because even though argument &ch is the correct type for the format string it accompanies, it is a pointer to only a single character of storage, and the fscanf will always write outside its bounds if it successfully scans a string (because it must write a string terminator even for a one-character string).
#BLUEPIXY's approach is much better, supposing that phrase[counter].word is a char array, but even there you risk overrunning its bounds. To protect yourself against that, specify a field width. For instance, if phrase[counter].word is an array of 20 chars, then use this ...
fscanf(fp, "%19s", phrase[counter].word);
... to ensure that scanf() does not write more than 20 chars (including a string terminator) to the array.

maybe...
void create_word(struct Word_setup phrase[], FILE *fp)
{
fscanf(fp, "%s", phrase[counter].word);
clean_word();
}

Related

Problem reading two strings with getchar() and then printing those strings in C

This is my code for two functions in C:
// Begin
void readTrain(Train_t *train){
printf("Name des Zugs:");
char name[STR];
getlinee(name, STR);
strcpy(train->name, name);
printf("Name des Drivers:");
char namedriver[STR];
getlinee(namedriver, STR);
strcpy(train->driver, namedriver);
}
void getlinee(char *str, long num){
char c;
int i = 0;
while(((c=getchar())!='\n') && (i<num)){
*str = c;
str++;
i++;
}
printf("i is %d\n", i);
*str = '\0';
fflush(stdin);
}
// End
So, with void getlinee(char *str, long num) function I want to get user input to first string char name[STR] and to second char namedriver[STR]. Maximal string size is STR (30 charachters) and if I have at the input more than 30 characters for first string ("Name des Zuges"), which will be stored in name[STR], after that I input second string, which will be stored in namedriver, and then printing FIRST string, I do not get the string from the user input (first 30 characters from input), but also the second string "attached" to this, I simply do not know why...otherwise it works good, if the limit of 30 characters is respected for the first string.
Here my output, when the input is larger than 30 characters for first string, problem is in the row 5 "Zugname", why I also have second string when I m printing just first one...:
Name des Zugs:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
i is 30
Name des Drivers:xxxxxxxx
i is 8
Zugname: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaxxxxxxxx
Drivername: xxxxxxxx
I think your issue is that your train->name is not properly terminated with '\0', as a consequence when you call printf("%s", train->name) the function keeps reading memory until it finds '\0'. In your case I guess your structure looks like:
struct Train_t {
//...
char name[STR];
char driver[STR];
//...
};
In getlinee() function, you write '\0' after the last character. In particular, if the input is more than 30 characters long, you copy the first 30 characters, then add '\0' at the 31-th character (name[30]). This is a first buffer overflow.
So where is this '\0' actually written? well, at name[30], even though your not supposed to write there. Then, if you have the structure above when you do strcpy(train->name, name); you will actually copy a 31-bytes long string: 30 chars into train->name, and the '\0' will overflow into train->driver[0]. This is the second buffer overflow.
After this, you override the train->driver buffer so the '\0' disappears and your data in memory basically looks like:
train->name = "aaa...aaa" // no '\0' at the end so printf won't stop reading here
train->driver = "xxx\0" // but there
You have an off-by-one error on your array sizes -- you have arrays of STR chars, and you read up to STR characters into them, but then you store a NUL terminator, requiring (up to) STR + 1 bytes total. So whenever you have a max size input, you run off the end of your array(s) and get undefined behavior.
Pass STR - 1 as the second argument to getlinee for the easiest fix.
Key issues
Size test in wrong order and off-by-one. ((c=getchar())!='\n') && (i<num) --> (i+1<num) && ((c=getchar())!='\n'). Else no room for the null character. Bad form to consume an excess character here.
getlinee() should be declared before first use. Tip: Enable all compiler warnings to save time.
Other
Use int c; not char c; to well distinguish the typical 257 different possible results from getchar().
fflush(stdin); is undefined behavior. Better code would consume excess characters in a line with other code.
void getlinee(char *str, long num) better with size_t num. size_t is the right size type for array sizing and indexing.
int i should be the same type as num.
Better code would also test for EOF.
while((i<num) && ((c=getchar())!='\n') && (c != EOF)){
A better design would return something from getlinee() to indicate success and identify troubles like end-of-file with nothing read, input error, too long a line and parameter trouble like str == NULL, num <= 0.
I believe you have a struct similar to this:
typedef struct train_s
{
//...
char name[STR];
char driver[STR];
//...
} Train_t;
When you attempt to write a '\0' to a string that is longer than STR (30 in this case), you actually write a '\0' to name[STR], which you don't have, since the last element of name with length STR has an index of STR-1 (29 in this case), so you are trying to write a '\0' outside your array.
And, since two strings in this struct are stored one after another, you are writing a '\0' to driver[0], which you immediately overwrite, hence when printing out name, printf doesn't find a '\0' until it reaches the end of driver, so it prints both.
Fixing this should be easy.
Just change:
while(((c=getchar())!='\n') && (i<num))
to:
while(((c=getchar())!='\n') && (i<num - 1))
Or, as I would do it, add 1 to array size:
char name[STR + 1];
char driver[STR + 1];

C - Using fgets until newline/-1 [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
So I'm trying to make it so that you can write text into a file until you make a newline or type -1. My problem is that when you write, it just keeps going until it crashes and gives the error "Stack around the variable "inputChoice" was corrupted".
I believe the problem is that the program doesn't stop accepting stdin when you want to stop typing (-1, newline) and that causes the error. I've tried with a simple scanf and it works, but you can only write a word. No spaces and it doesn't support multiple lines either. That's why I have to use fgets
Judging from your comments, I assume that there are some basic concepts in C
that you haven't fully understood, yet.
C-Strings
A C-String is a sequence of bytes. This sequence must end with the value 0.
Every value in the sequence represents a character based on the
ASCII encoding, for example the
character 'a' is 97, 'b' is 98, etc. The character '\0' has
the value 0 and it's the character that determines the end of the string.
That's why you hear a lot that C-Strings are '\0'-terminated.
In C you use an array of chars (char string[], char string[SOME VALUE]) to
save a string. For a string of length n, you need an array of dimension n+1, because
you also need one space for the terminating '\0' character.
When dealing with strings, you always have to think about the proper type,
whether your are using an array or a pointer. A pointer
to char doesn't necessarily mean that you are dealing with a C-String!
Why am I telling you this? Because of:
char inputChoice = 0;
printf("Do you wish to save the Input? (Y/N)\n");
scanf("%s", &inputChoice);
I haven't changed much, got very demotivated after trying for a while.
I changed the %s to an %c at scanf(" %c, &inputChoice) and that
seems to have stopped the program from crashing.
which shows that haven't understood the difference between %s and %c.
The %c conversion specifier character tells scanf that it must match a single character and it expects a pointer to char.
man scanf
c
Matches a sequence of characters whose length is specified by the maximum field
width (default 1); the next pointer must be a
pointer to char, and there must be enough room for all the characters
(no terminating null byte is added). The usual skip of
leading white space is suppressed. To skip white space first, use an explicit space in the format.
Forget the bit about the length, it's not important right now.
The important part is in bold. For the format scanf("%c", the function
expects a pointer to char and its not going to write the terminating '\0'
character, it won't be a C-String. If you want to read one letter and one
letter only:
char c;
scanf("%c", &c);
// also possible, but only the first char
// will have a defined value
char c[10];
scanf("%c", c);
The first one is easy to understand. The second one is more interesting: Here
you have an array of char of dimension 10 (i.e it holds 10 chars). scanf
will match a single letter and write it on c[0]. However the result won't be
a C-String, you cannot pass it to puts nor to other functions that expect
C-Strings (like strcpy).
The %s conversion specifier character tells scanf that it must match a sequence of non-white-space characters
man scanf
s
Matches a sequence of non-white-space characters; the next pointer must be a
pointer to the initial element of a character array that is long enough to
hold the input sequence and the terminating null byte ('\0'), which is added
automatically.
Here the result will be that a C-String is saved. You also have to have enough
space to save the string:
char string[10];
scanf("%s", string);
If the strings matches 9 or less characters, everything will be fine, because
for a string of length 9 requires 10 spaces (never forget the terminating
'\0'). If the string matches more than 9 characters, you won't have enough
space in the buffer and a buffer overflow (accessing beyond the size) occurs.
This is an undefined behaviour and anything can happen: your program might
crash, your program might not crash but overwrites another variable and thus
scrwes the flow of your program, it could even kill a kitten somewhere, do
you really want to kill kittens?
So, do you see why your code is wrong?
char inputChoice = 0;
scanf("%s", &inputChoice);
inputChoice is a char variable, it can only hold 1 value.
&inputChoice gives you the address of the inputChoice variable, but the
char after that is out of bound, if you read/write it, you will have an
overflow, thus you kill a kitten. Even if you enter only 1 character, it will
write at least 2 bytes and because you it only has space for one character, a kitten will die.
So, let's talk about your code.
From the perspective of an user: Why would I want to enter lines of text, possibly a lot of lines of text
and then answer "No, I don't want to save the lines". It doesn't make sense to
me.
In my opinion you should first ask the user whether he/she wants to save the
input first, and then ask for the input. If the user doesn't want to save
anything, then there is no point in asking the user to enter anything at
all. But that's just my opinion.
If you really want to stick to your plan, then you have to save every line and
when the user ends entering data, you ask and you save the file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFERLEN 1024
void printFile () {
int i;
char openFile[BUFFERLEN];
FILE *file;
printf("What file do you wish to write in?\n");
scanf("%s", openFile);
getchar();
file = fopen(openFile, "w");
if (file == NULL) {
printf("Could not open file.\n");
return;
}
// we save here all lines to be saved
char **lines = NULL;
int num_of_lines = 0;
char buffer[BUFFERLEN];
printf("Enter an empty line of -1 to end input\n");
// for simplicity, we assume that no line will be
// larger than BUFFERLEN - 1 chars
while(fgets(buffer, sizeof buffer, stdin))
{
// we should check if the last character is \n,
// if not, buffer was not large enough for the line
// or the stream closed. For simplicity, I will ignore
// these cases
int len = strlen(buffer);
if(buffer[len - 1] == '\n')
buffer[len - 1] = '\0';
if(strcmp(buffer, "") == 0 || strcmp(buffer, "-1") == 0)
break; // either an empty line or user entered "-1"
char *line = strdup(buffer);
if(line == NULL)
break; // if no more memory
// process all lines that already have been entered
char **tmp = realloc(lines, (num_of_lines+1) * sizeof *tmp);
if(tmp == NULL)
{
free(line);
break; // same reason as for strdup failing
}
lines = tmp;
lines[num_of_lines++] = line; // save the line and increase num_of_lines
}
char inputChoice = 0;
printf("Do you wish to save the Input? (Y/N)\n");
scanf("%c", &inputChoice);
getchar();
if (inputChoice == 'Y' || inputChoice == 'y') {
for(i = 0; i < num_of_lines; ++i)
fprintf(file, "%s\n", lines[i]); // writing every line
printf("Your file has been saved\n");
printf("Please press any key to continue");
getchar();
}
// closing FILE buffer
fclose(file);
// free memory
if(num_of_lines)
{
for(i = 0; i < num_of_lines; ++i)
free(lines[i]);
free(lines);
}
}
int main(void)
{
printFile();
return 0;
}
Remarks on the code
I used the same code as yours as the base for mine, so that you can spot the
differences much quicker.
I use the macro BUFFERLEN for declaring the length of the buffers. That's
my style.
Look at the fgets line:
fgets(buffer, sizeof buffer, stdin)
I use here sizeof buffer instead of 1024 or BUFFERLEN. Again, that's my
style, but I think doing this is better, because even if you change the size
of the buffer by changing the macro, or by using another explicit size, sizeof buffer
will always return the correct size. Be aware that this only works when
buffer is an array.
The function strdup returns a pointer a pointer to a new string that
duplicates the argument. It's used to create a new copy of a string. When
using this function, don't forget that you have to free the memory using
free(). strdup is not part of the standard library, it conforms
to SVr4, 4.3BSD, POSIX.1-2001. If you use Windows (I don't use Windows,
I'm not familiar with the Windows ecosystem), this function might not be
present. In that case you can write your own:
char *strdup(const char *s)
{
char *str = malloc(strlen(s) + 1);
if(str == NULL)
return NULL;
strcpy(str, s);
return str;
}

How to convert gchar* to char

When I press a key(integer) on my keyboard. It does something like:
gchar *keypressed;
keypressed=gdk_keyval_name (event->keyval);
printf("The KeyEvent is: %s\n", keypressed); // Till here it is fine
I get segmentation fault when I do this:
char ch;
sprintf(ch, "%s\n", keypressed);
printf("The NewKeyEvent is: %s\n",ch);
I need to convert it as I am going to use the value in a switch case. Without converting it is not possible.
gchar is a typedef alias of char, so the problem is not with the type conversion. You need to allocate some space for the sprintf buffer.
Currently, you are passing a single uninitialized char to where a pointer should be. You should get a warning from the compiler, in addition to a segfault caused by undefined behavior.
To fix this, make an array of chars and pass it to sprintf instead:
char ch[10];
sprintf(ch, "%8s\n", keypressed);
printf("The NewKeyEvent is: %s\n", c);
Note the limit of 8 in the sprintf. This is because ch is of size 10, and we need two extra spots for '\n' and '\0'.
If you want only a single character from the keypressed string there are two ways:
Use array indexing, this way you can access any character in the string:
char ch = keypressed[x]; // Where `x` is the character number you want
Remember that array indexing starts from zero, so the first character in the string is number 0.
If you want the first character, you can also use the dereference operator
char ch = *keypressed;
This equivalent to
char ch = keypressed[0];

Comparing 2 Strings, one in a struct other not C programming

I have this database and I Need to check whether a Product Name is already in the database otherwise I ask the user to input another one.
The problem is this:
I'm trying to compare a string (the Product Name) found inside the struct with the string the user inputs.
The coding of the struct, the user input part and the search method are here below:
product Structure
typedef struct
{
char pName[100];
char pDescription [100];
float pPrice;
int pStock;
int pOrder;
}product;
the checkProduct method:
int checkProduct (char nameCheck[100])
{
product temp;
p.pName = nameCheck;
rewind (pfp);
while (fread(&temp,STRUCTSIZE,1,pfp)==1)
{
if (strcmp (temp.pName,p.pName))
{
return 1;
}
}
return 0;
}
and the user input part [part of the code]:
char nameCheck[100];
gets (nameCheck);
checkProduct (nameCheck);
while (checkProduct == 1)
{
printf ("Product Already Exists!\n Enter another!\n");
while (getchar() !='\n')
{
continue;
}
}
p.pName = nameCheck;
Now I am having the following errors (I Use ECLIPSE):
on the line
while (checkProduct == 1) [found in the user input] is giving me:
"comparison between pointer and integer - enabled by default" marked by a yellow warning triangle
p.pName = nameCheck; is marked as a red cross and stopping my compiling saying:
"incompatible types when assigning to type 'char [100] from type 'char*'
^---- Is giving me trouble BOTH in the userinput AND when I'm comparing strings.
Any suggestions how I can fix it or maybe how I can deference it? I can't understand why in the struct the char pName is being marked as '*' whereas in the char[100] it's not.
Any brief explanation please?
Thank you in advance
EDIT: After emending the code with some of below:
THIS Is the INPUT NAME OF PRODUCT section;
char *nameCheck;
nameCheck = "";
fgets(nameCheck,sizeof nameCheck, stdin);
checkProduct (nameCheck);
int value = checkProduct (nameCheck);
while (value == 1)
{
printf ("Product Already Exists!\n Enter another!\n");
while (getchar() !='\n')
{
}
}
strcpy (p.pName, nameCheck);
this is the new checkName method
int checkProduct (char *nameCheck)
{
product temp;
strcpy (p.pName, nameCheck);
rewind (pfp);
while (fread(&temp,STRUCTSIZE,1,pfp)==1)
{
if (strcmp (temp.pName,p.pName) == 0)
{
return 1;
}
}
return 0;
}
p.pName = nameCheck;
is wrong as you try to assign address of one array to another. What you probably want is to copy it.
Use strcpy() instead.
strcpy(p.pName, nameCheck);
while (checkProduct == 1)
Since checkProduct is a function, the above condition will always be false as the address of function won't be equal to 1. You can store the return value in another integer like this:
int value = checkProduct(nameCheck);
while (value == 1)
/* rest of the code */
Or rather simply:
while ( checkProduct(nameCheck) == 1 ) {
...
Note - I've not checked entire code, there might be other bugs apart from this one. Btw, if you are new to programming, you can start with small examples from textbooks and then work towards slightly complex stuff.
int checkProduct (char nameCheck[100])
Note that the type signature is a lie. The signature should be
int checkProduct(char *nameCheck)
since the argument the function expects and receives is a pointer to a char, or, to document it for the user that the argument should be a pointer to the first element of a 0-terminated char array
int checkProduct(char nameCheck[])
Arrays are never passed as arguments to functions, as function arguments, and in most circumstances [the exceptions are when the array is the operand of sizeof, _Alignof or the address operator &] are converted to pointers to the first element.
{
product temp;
p.pName = nameCheck;
Arrays are not assignable. The only time you can have an array name on the left of a = is initialisation at the point where the array is declared.
You probably want
strcpy(p.pName, nameCheck);
there.
rewind (pfp);
while (fread(&temp,STRUCTSIZE,1,pfp)==1)
{
if (strcmp (temp.pName,p.pName))
strcmp returns a negative value if the first argument is lexicographically smaller than the second, 0 if both arguments are equal, and a positive value if the first is lexicographically larger than the second.
You probably want
if (strcmp(temp.pName, p.pName) == 0)
there.
gets (nameCheck);
Never use gets. It is extremely unsafe (and has been remoed from the language in the last standard, yay). Use
fgets(nameCheck, sizeof nameCheck, stdin);
but that stores the newline in the buffer if there is enough space, so you have to overwrite that with 0 if present.
If you are on a POSIX system and don't need to care about portability, you can use getline() to read in a line without storing the trailing newline.
checkProduct (nameCheck);
You check whether the product is known, but throw away the result. Store it in a variable.
while (checkProduct == 1)
checkProduct is a function. In almost all circumstances, a function designator is converted into a pointer, hence the warning about the comparison between a pointer and an integer. You meant to compare to the value of the call you should have stored above.
{
printf ("Product Already Exists!\n Enter another!\n");
while (getchar() !='\n')
You read in characters without storing them. So you will never change the contents of nameCheck, and then be trapped in an infinite loop.
{
continue;
}
If the only statement in a loop body is continue;, you should leave the body empty.
}
p.pName = nameCheck;
Once again, you can't assign to an array.
Concerning the edit,
char *nameCheck;
nameCheck = "";
fgets(nameCheck,sizeof nameCheck, stdin);
you have changed nameCheck from an array to a pointer. That means that sizeof nameCheck now doesn't give the number of chars you can store in the array, but the size of a pointer to char, which is independent of what it points to (usually 4 on 32-bit systems and 8 on 64-bit systems).
And you let that pointer point to a string literal "", which is the reason for the crash. Attempting to modify string literals is undefined behaviour, and more often than not leads to a crash, since string literals are usually stored in a read-only segment of the memory nowadays.
You should have left it at
char nameCheck[100];
fgets(nameCheck, sizeof nameCheck, stdin);
and then you can use sizeof nameCheck to tell fgets how many characters it may read, or, alternatively, you could have a pointer and malloc some memory,
#define NAME_LENGTH 100
char *nameCheck = malloc(NAME_LENGTH);
if (nameCheck == NULL) {
// malloc failed, handle it if possible, or
exit(EXIT_FAILURE);
}
fgets(nameCheck, NAME_LENGTH, stdin);
Either way, after getting input, remove the newline if there is one:
size_t len = strlen(nameCheck);
if (len > 0 && nameCheck[len-1] == '\n') {
nameCheck[len-1] = 0;
}
// Does windows also add a '\r' when reading from stdin?
if (len > 1 && nameCheck[len-2] == '\r') {
nameCheck[len-2] = 0;
}

File I/O difficulties in C

I'm writing a version of the Unix expand utility that replaces tabs with spaces in a file. To do this, I'm reading in each character and testing if it is a tab character. If it is, it replaces the tab with the given amount of spaces, otherwise the character gets printed.
My main method goes like
int main(int argc, char *argv[]){
FILE *fp;
char *help1="-help";
char *help2= "--help";
//int spaces; //number of spaces to replace tabs
fp= fopen(argv[1], "rw");
parse_file(fp, 4);
fclose(fp);
return 0;
}
the parse_file method goes like
void parse_file(FILE *fp, int spaces)
{
int i; //loop counter
char c; //current character
while (c!= EOF)
{
c= getchar(); //get char from stream
if (c=='\t') //if char is a tab
{
for (i=0; i< spaces; i++)
putchar(" "); //replace with spaces
}
else
putchar(c); //otherwise, print the character
}
}
When compiling, I get an integer from pointer without cast warning for putchar(" "); and the program hits a segfault when executing.
So, my questions:
1- What is the warning "makes integer from pointer without cast" all about? What can I do to resolve it?
2- The code generates a segfault on execution with a text file passed in as an argument. Is there anything in this code that would cause that?
you must use
putchar(' ')
instead
putchar(" ")
You're calling putchar on a string (" "), but it wants a char argument (' '). (Actually an int, but only passing a char is safe.)
The segfault is probably due to the fclose on fp, which may be NULL. You should check the return value from fopen. The reason you only notice after parse_file is that it doesn't touch fp at all (it reads from stdin and writes to stdout). To use the stream fp, you should use getc(fp) and putc(fp) instead. (That still won't work because you'd overwrite the stream with more data than you're reading from it, so you'll get garbage out.)
In fact, the program is sure to segfault when no command line argument is given. Either fopen segfaults because it is handed the null pointer argv[1], or it returns a null pointer itself.
When writing these kinds of programs, please adhere to the Unix philosophy and write them as filters: read from stdin, write to stdout. Don't modify a file in-place if you don't have to.
In C string literals are of type char *, a pointer to some area containing string characters.
" " is a string literal, not a character. Use ' ' when you need a single character
As everyone else says, re. The use of char vs. string. As for the logic behind the actual error message you see, the string is a pointer to a const array of characters. Hence the error is saying it is converting the pointer to an int. Most of the char functions work with ints.
To summarise the issues (I'm repeating stuff other people have said, but issues 5 and 6 havehas not been mentioned so far):
putchar() does not take a string pointer as an argument but an int - the constant ' ' is an acceptable parameter
you don't check that argc > 1 before using argv[1]
you don't check that fopen() successfully opens the file
c should be defined as an int since in some character sets (char) -1 (0xFF) is a legitimate character and also the comparison c == EOF may fail if c is not sign extended
The first time through the loop c is used uninitialised and in the loop you also treat EOF as a normal character. The normal idiom in C programs is
int c;
while ((c = fgetc(fp)) != EOF)
{
// do stuff with c
}
You are getting your characters from stdin and not fp hence use fgetc() not getchar()
I think that covers everything.
To answer your explicit question, you get the warning "makes integer from pointer without cast" when an int is expected but you use a pointer (in this case the type of " " is const char*).
In addition to what has already been said, getchar() returns int not char. EOF is an int constant. You will need to read the result from getchar() into an int, check for EOF, and if not found, cast the int into a char.

Resources