How to check for an empty character pointer in C - c

I'm recently working on simple chess game on the terminal using C, but I've ran into a small issue in regard to taking user input.
The following function takes in a 3-Dimensional array containing current chess piece placements, a pointer to a buffer that'll contain the user input, and the size of this buffer which I set to 7.
void next_move(char board[8][8][4], char* move, size_t buff_size){
char * move_1 = (char )malloc(sizeof(char)3);
char * move_2 = (char )malloc(sizeof(char)3);
char delim[]=" ";
getline(&move,&buff_size,stdin);
move_1=strtok(move,delim);
move_2=strtok(NULL,delim);
if(*move_1 == '\0'){
printf("invalid move !");
return ;
}
printf("%s%s\n",move_1,move_2);
if(!check_move(board, move_1, move_2)){
printf("valid move !\n");
}
}
The function check_move takes in both moves inputted by the user and verifies if they're valid chess moves (E.g "Nb1 Nc3").
My issue lies in the fact that when the user inputs no character or a string of characters not containing a space (the delimeter defined in strtok) it results in a segmentation fault when I try to do the check:
if(*move_1 == '\0')
Which is used mainly to handle the exception in the case that the move_1 and move_2 pointers are null.
I have two questions:
How can I check if a char pointer is null ? (I have already tried using move_1 == NULL)
Why the does the code continue execution and returns if I set the conditional statement to if(*move_1 != 0). Although this causes all input (even if it's the correct format) to not be valid.

Question 1
It sounds like maybe move is NULL, but your first call to strtok is supposed to have a non-NULL pointer. Therefore, right after you call getline, I think you should check to make sure move is not NULL. It would also be a good idea to check that move_1 and move_2 are not NULL. You can do these checks with code like this:
getline(&move,&buff_size,stdin);
if (move == NULL) {
// handle this case, probably with an early return
}
Note that the code above only shows a check for move, but I think you should probably do the same thing for move_1 and move_2, right after you assign to them, and before you use them or derefence them. (Some of these checks might turn out to be unnecessary upon further investigation, but for now I think the priority is to just fix all the segmenation faults so your program can run without crashing.)
Question 2
It sounds like you changed your code to the following and it started declaring all your input as invalid:
if(*move_1 != '\0'){
printf("invalid move !");
return;
}
Well, the explanation for that is simple. You are telling your compiler that if the first character of the move_1 string is not a null-termination character, that it should print "invalid move !" and return. Therefore, whenever move_1 is non-empty, it will do that. Maybe you meant to use == (equal) instead of != (not equals).

If you mean by entering no characters that you are pressing enter that means your condition should be like: if(*move_1 == '\n'), since the Enter in a new line feed to the command line which is '\n' escape character.
I wish I can see your full project and work together to complete it...

Related

Use scanf to get commands and arguments in C

I need to create a method that get's commands from users using scanf and runs a function. The command can be simple as help or list but it can also be a command that has an argument like look DIRECTION or take ITEM. What is the best way to go about this? I could just loop through the characters of a single given string and check it manually but I was wondering there was a better way of doing this.
scanf("%s %s", command, argument);
This won't work if there's no argument. Is there a way around this?
There is a 'method' that may work. In fact, two come to mind.
Both rely on whitespace chars (in plain-english, '\n', ' 'and '\t') separating the arguments , and I assume this is good enough.
1
First, the relatively easy one - using main(int argc,char *argv[]) as most CLI programs do.
Then, running a long string of if()s/else if()s which check if the input string matched valid arguments , by testing if strcmp(argv[x],expected_command) returns 0.
You may not yet have been taught about how to use this, and it may appear scary, but its quite easy if you are familiar with string.h, arrays and pointers already.
Google searches and YouTube videos may be of help, and it won't take more than 20 or so minutes.
2
Second, if you have your program with a real CLU 'UI' and the program is in a loop and doesn't just terminate once output is generated - unlike say cat or ls , then you take input of 'command' strings within the program.
This means you will have to, apart from and before the if-ed strcmp()s , ensure that you take input with scanf() safely, and that you are able to take multiple strings as input, since you talk of sub-arguments like look DIRECTION.
The way I have done this myself (in the past) is as follows :
1. Declare a command string, say char cmd[21] = ""; and (optionally) initialise it to be empty , since reading an uninitialised string is UB (and the user may enter EOF).
2. Declare a function (for convenience) to check scanf() say like so:
int handle_scanf(int returned,int expected){
if(returned==expected)
return 0;
if(returned==EOF){
puts("\n Error : Input Terminated Immaturely.");
/* you may alternatively do perror() but then
will have to deal with resetting errno=0 and
including errno.h */
return -1;
}
else{
puts("\n Error : Insufficient Input.");
return -2;
}
}
Which can be used as : if(handle_scanf(scanf(xyz,&xyz),1)==0) {...}
As scanf() returns number of items 'taken' (items that matched with expected format-string and were hence saved) and here there is only 1 expected argument.
3. Declare a function (for convenience) to clear/flush stdin so that if and when unnecessary input is left in the input stream , (which if not dealt with, will be passed to the next place where input is taken) it can be 'eaten'.
I do it like so :
void eat()
{
int eat; while ((eat = getchar()) != '\n' && eat != EOF);
}
Essentially clears input till a newline or EOF is read. Since '\n' and EOF represent End Of Line and End Of File , and modern I/O is line buffered and performed through the stdin file , it makes sense to stop upon reading them.
EDIT : You may alternatively use a macro, for slightly better performance.
4. Print a prompt and take input, like so :
fputs("\n >>> ",stdout);
int check = handle_scanf(scanf("%20s",cmd),1);
Notice what I did here ?
"%20s" does two things - stops buffer overflow (because more than 20 chars won't be scanned into cmd) and also stops scanning when a whitespace char is encountered. So, your main command must be one-word.
5. Check if the the command is valid .
This is to be done with the aforementioned list of checking if strcmp(cmd,"expected_cmd")==0 , for all possible expected commands.
If there is no match, with an else , display an error message and call eat();(arguments to invalid command can be ignored) but only if(check != -1).
If check==-1 , this may mean that the user has sent an EOF signal to the program, in which case, calling eat() within a loop will result in an infinite loop displaying the error message, something which you don't want.
6. If there is a match, absorb the whitespace separating char and then scanf() into a char array ( if the user entered, look DIRECTION, DIRECTION is still in the input stream and will only now be saved to said char array ). This can be done like so :
#define SOME_SIZE 100 // use an appropriate size
if(strcmp(cmd,"look")==0 && check==0){ // do if(check==0) before these ifs, done here just for my convenience)
getchar(); // absorb whitespace seperator
char strbuff[SOME_SIZE] = ""; // string buffer of appropriate size
if(handle_scanf(scanf("%99[^\n]",strbuff),1)==0){
eat();
/* look at DIRECTION :) */
}
// handle_scanf() generated appropriate error msg if it doesn't return 0
}
Result
All in all, this code handles scanf mostly safely and can indeed be used in a way that the user will only type , say :
$ ./myprogram
>>> look DIRECTION
# output
>>> | #cursor
If it is all done within a big loop inside main() .
Conclusion
In reality, you may end up needing to use both together if your program is complex enough :)
I hope my slightly delayed answer is of help :)
In case of any inaccuracies , or missing details, please comment and I will get back to you ASAP
Here's a good way to parse an inputted string using strtok and scanf with a limit of 99 characters
#include <string.h>
char command[99];
scanf("%[^\n]%*c", command); //This gets the entire string and spaces
char *token;
token = strtok(command, " "); //token = the first string separated by a " "
if (strcmp(token, "help") == 0){
//do function
}
else if (strcmp(token, "go") == 0){ //if the command has an argument, you have to get the next string
token = strtok(NULL, " "); //this gets the next string separated by a space
if (strcmp(token, "north") == 0){
//do function
}
}
You can keep using token = strtok(NULL, " "); until token = NULL signifying the end of a string

getchar() keeps reading a '\n'. What is going on?

I have a small program I'm writing to practice programming in C.
I want it to use the getchar(); function to get input from the user.
I use the following function to prompt for user input, then loop using getchar() to store input in an array:
The function is passed a pointer referencing a struct's member.
getInput(p->firstName); //The function is passed an argument like this one
void getInput(char * array)
{
int c;
while((c=getchar()) != '\n')
*array++ = c;
*array = '\0'; //Null terminate
}
This function is called multiple times, as it is a part of a function that creates a structure, and populates it's array members.
However when the program executes, The first two calls to it work fine, but any subsequent calls to this function will cause every-other call to getchar() to not wait for keyboard input.
After some debugging I traced the bug to be that getchar(); was for some reason reading in the '\n' character instead of waiting for input, the while loop test fails, and the function returns essentially an empty string.
I have done some research and keep finding to use
while(getchar() != '\n');
at the end of the function in order to properly flush stdin, however, this produces undesirable results, as the program will prompt again for more input after I type ENTER. Pressing ENTER again continues the program, but every-other subsequent calls continue to read in this mysterious '\n' character right off the bat, causing the test to fail, and resulting in empty strings whenever it comes time to print the contents of the the structure.
Could anyone explain to me what is going on here? Why does getchar() keep fetching a '\n' even though I supposedly cleared the input buffer? I have tried just placing a getchar(); statement at the beginning and end of the function, tried 'do while' loops, and taken other jabs at it, but I can't seem to figure this out.
The code you have written has several drawbacks. I'll try to explain them as it is unclear where your code is failing (probably outside the function you posted)
First of all, you don't check for EOF in getchar() result value. getchar(3) doesn't return a char precisely to allow to return al possible char values plus an extra one, EOF, to mark the end of file (this can be generated from a terminal by input of Ctrl-D in unix, or Ctrl-Z on windows machines) That case must be explicitly contempled in your code, as you'll convert the result to a char and will lose the extra information you received from the function. Read getchar(3) man page to solve this issue.
Second, you don't check for input of enough characters to fill all the array and overflow it. To the function you pass only a pointer to the beginning of the array, but nothing indicates how far it extends, so you can be overfilling past the end of its bounds, just overwritting memory that was not reserved for input purposes. This normally results in something called U.B. in the literature (Undefined Behaviour) and is something you must care of. This can be solved by passing a counter of valid positions to fill in the array and decrementing it for each valid position filled. And not allowing more input once the buffer has filled up.
On other side, you have a standar function that does exactly that, fgets(3) just reads one string array from an input file, and stores it on the pointer (and size) you pass to it:
char *fgets(char *buffer, size_t buffer_size, FILE *file_descriptor);
You can use it as in:
char buffer[80], *line;
...
while (line = fgets(buffer, sizeof buffer, stdin)) {
/* process one full line of input, with the final \n included */
....
}
/* on EOF, fgets(3) returns NULL, so we shall be here after reading the
* full input file */

Checking contents of char variable - C Programming

This might seem like a very simple question, but I am struggling with it. I have been writing iPhone apps with Objective C for a few months now, but decided to learn C Programming to give myself a better grounding.
In Objective-C if I had a UILabel called 'label1' which contained some text, and I wanted to run some instructions based on that text then it might be something like;
if (label1.text == #"Hello, World!")
{
NSLog(#"This statement is true");
}
else {
NSLog(#"Uh Oh, an error has occurred");
}
I have written a VERY simple C Program I have written which uses printf() to ask for some input then uses scanf() to accept some input from the user, so something like this;
int main()
{
char[3] decision;
Printf("Hi, welcome to the introduction program. Are you ready to answer some questions? (Answer yes or no)");
scanf("%s", &decision);
}
What I wanted to do is apply an if statement to say if the user entered yes then continue with more questions, else print out a line of text saying thanks.
After using the scanf() function I am capturing the users input and assigning it to the variable 'decision' so that should now equal yes or no. So I assumed I could do something like this;
if (decision == yes)
{
printf("Ok, let's continue with the questions");
}
else
{
printf("Ok, thank you for your time. Have a nice day.");
}
That brings up an error of "use of undeclared identifier yes". I have also tried;
if (decision == "yes")
Which brings up "result of comparison against a string literal is unspecified"
I have tried seeing if it works by counting the number of characters so have put;
if (decision > 3)
But get "Ordered comparison between pointer and integer 'Char and int'"
And I have also tried this to check the size of the variable, if it is greater than 2 characters it must be a yes;
if (sizeof (decision > 2))
I appreciate this is probably something simple or trivial I am overlooking but any help would be great, thanks.
Daniel Haviv's answer told you what you should do. I wanted to explain why the things you tried didn't work:
if (decision == yes)
There is no identifier 'yes', so this isn't legal.
if (decision == "yes")
Here, "yes" is a string literal which evaluates to a pointer to its first character. This compares 'decision' to a pointer for equivalence. If it were legal, it would be true if they both pointed to the same place, which is not what you want. In fact, if you do this:
if ("yes" == "yes")
The behavior is undefined. They will both point to the same place if the implementation collapses identical string literals to the same memory location, which it may or may not do. So that's definitely not what you want.
if (sizeof (decision > 2))
I assume you meant:
if( sizeof(decision) > 2 )
The 'sizeof' operator evaluates at compile time, not run time. And it's independent of what's stored. The sizeof decision is 3 because you defined it to hold three characters. So this doesn't test anything useful.
As mentioned in the other answer, C has the 'strcmp' operator to compare two strings. You could also write your own code to compare them character by character if you wanted to. C++ has much better ways to do this, including string classes.
Here's an example of how you might do that:
int StringCompare(const char *s1, const char *s2)
{ // returns 0 if the strings are equivalent, 1 if they're not
while( (*s1!=0) && (*s2!=0) )
{ // loop until either string runs out
if(*s1!=*s2) return 1; // check if they match
s1++; // skip to next character
s2++;
}
if( (*s1==0) && (*s2==0) ) // did both strings run out at the same length?
return 0;
return 1; // one is longer than the other
}
You should use strcmp:
if(strcmp(decision, "yes") == 0)
{
/* ... */
}
You should be especially careful with null-terminated string in C programming. It is not object. It is a pointer to a memory address. So you can't compare content of decision directly with a constant string "yes" which is at another address. Use strcmp() instead.
And be careful that "yes" is actually "yes\0" which will take 4 bytes and the "\0" is very important to strcmp() which will be recognized as the termination during the comparison loop.
Ok a few things:
decision needs to be an array of 4 chars in order to fit the string "yes" in it. That's because in C, the end of a string is indicated by the NUL char ('\0'). So your char array will look like: { 'y', 'e', 's', '\0' }.
Strings are compared using functions such as strcmp, which compare the contents of the string (char array), and not the location/pointer. A return value of 0 indicates that the two strings match.
With: scanf("%s", &decision);, you don't need to use the address-of operator, the label of an array is the address of the start of the array.
You use strlen to get the length of a string, which will just increment a counter until it reaches the NUL char, '\0'. You don't use sizeof to check the length of strings, it's a compile-time operation which will return the value 3 * sizeof(char) for a char[3].
scanf is unsafe to use with strings, you should alternatively use fgets(stdin...), or include a width specifier in the format string (such as "3%s") in order to prevent overflowing your buffer. Note that if you use fgets, take into account it'll store the newline char '\n' if it reads a whole line of text.
To compare you could use strcmp like this:
if(strcmp(decision, "yes") == 0) {
// decision is equal to 'yes'
}
Also you should change char decision[3] into char decision[4] so that the buffer has
room for a terminating null character.
char decision[4] = {0}; // initialize to 0
There's several issues here:
You haven't allocated enough storage for the answer:
char[3] decision;
C strings are bytes in the string followed by an ASCII NUL byte: 0x00, \0. You have only allocated enough space for ye\0 at this point. (Well, scanf(3) will give you yes\0 and place that NUL in unrelated memory. C can be cruel.) Amend that to include space for the terminating \0 and amend your scanf(3) call to prevent the buffer overflow:
char[4] decision;
/* ... */
scanf("%3s", decision);
(I've left off the &, because simply giving the name of the array is the same as giving the address of its first element. It doesn't matter, but I believe this is more idiomatic.)
C strings cannot be compared with ==. Use strcmp(3) or strncmp(3) or strcasecmp(3) or strncasecmp(3) to compare your strings:
if(strcasecmp(decision, "yes") == 0) {
/* yes */
}
C has lots of lib functions to handle this but it pays to know what you are declaring.
Declaring
char[3] decision;
is actually declaring a char array of length 3. So therefor attempting a comparison of
if(decision == "yes")
is comparing a literal against and array and therefor will not work. Since there is no defined string type in C you have to use pointers, but not directly, if you don't want to. In C strings are in fact arrays of char so you can declare them both ways eg:
char[3] decision ;
* char decision ;
Both will in point of fact work but you in the first instance the compiler will allocate the memory for you, but it will ONLY allocate 3 bytes. Now since strings in C are null terminated you need to actually allocate 4 bytes since you need room for "yes" and the null. Declaring it the second way simply declares a pointer to someplace in memory but you have no idea really where. You would then have to allocate memory to contain whatever you are going to put there since to do otherwise will more then likely cause a SEGFAULT.
To compare what you get from input you have two options, either use the strcomp() function or do it yourself by iterating through decision and comparing each individual byte against "Y" and "E" and "S" until you hit null aka \0.
There are variations on strcomp() to deal with uppercase and lowercase and they are part of the standard string.h library.

Looping until a specific string is found

I have a simple question. I want to write a program in C that scans the lines of a specific file, and if the only phrase on the line is "Atoms", I want it to stop scanning and report which line it was on. This is what I have and is not compiling because apparently I'm comparing an integer to a pointer: (of course "string.h" is included.
char dm;
int test;
test = fscanf(inp,"%s", &dm);
while (test != EOF) {
if (dm=="Amit") {
printf("Found \"Atoms\" on line %d", j);
break;
}
j++;
}
the file was already opened with:
inp = fopen( .. )
And checked to make sure it opens correctly...
I would like to use a different approach though, and was wondering if it could work. Instead of scanning individual strings, could I scan entire lines as such:
// char tt[200];
//
// fgets(tt, 200, inp);
and do something like:
if (tt[] == "Atoms") break;
Thanks!
Amit
Without paying too much attention to your actual code here, the most important mistake your making is that the == operator will NOT compare two strings.
In C, a string is an array of characters, which is simply a pointer. So doing if("abcde" == some_string) will never be true unless they point to the same string!
You want to use a method like "strcmp(char *a, char *b)" which will return 0 if two strings are equal and something else if they're not. "strncmp(char *a, char *b, size_t n)" will compare the first "n" characters in a and b, and return 0 if they're equal, which is good for looking at the beginning of strings (to see if a string starts with a certain set of characters)
You also should NOT be passing a character as the pointer for %s in your fscanf! This will cause it to completely destroy your stack it tries to put many characters into ch, which only has space for a single character! As James says, you want to do something like char ch[BUFSIZE] where BUFSIZE is 1 larger than you ever expect a single line to be, then do "fscanf(inp, "%s", ch);"
Hope that helps!
please be aware that dm is a single char, while you need a char *
more: if (dm=="Amit") is wrong, change it in
if (strcmp(dm, "Amit") == 0)
In the line using fscanf, you are casting a string to the address of a char. Using the %s in fscanf should set the string to a pointer, not an address:
char *dm;
test = fscanf(inp,"%s", dm);
The * symbol declares an indirection, namely, the variable pointed to by dm. The fscanf line will declare dm as a reference to the string captured with the %s delimiter. It will point to the address of the first char in the string.
What kit said is correct too, the strcmp command should be used, not the == compare, as == will just compare the addresses of the strings.
Edit: What kit says below is correct. All pointers should be allocated memory before they are used, or else should be cast to a pre-allocated memory space. You can allocate memory like this:
dm = (char*)malloc(sizeof(char) * STRING_LENGTH);
where STRING_LENGTH is a maximum length of a possible string. This memory allocation only has to be done once.
The problem is you've declared 'dm' as a char, not a malloc'd char* or char[BUFSIZE]
http://www.cplusplus.com/reference/clibrary/cstdio/fscanf/
You'll also probably report incorrect line numbers, you'll need to scan the read-in buffer for '\n' occurences, and handle the case where your desired string lies across buffer boundaries.

why does this happen (see image)?

Why does the following have the effect it does - it prints a terminal full of random characters and then exits leaving a command prompt that produces garbage when you type in it. (I tried it because I thought it would produce a seg fault).
#include <stdio.h>
int main(){
char* s = "lololololololol";
while(1){
printf("%c", *s);
s++;
}
}
it was compiled with:
gcc -std=c99 hello.c
It will eventually seg fault, but before that it'll print out whatever bytes are in the same page. That's why you see random chars on the screen.
Those may well include escape sequences to change (say) the character encoding of the console. That's why you end up with gibberish when you type on the console after it's exited, too.
Because you have an infinite loop (while(1)), and you keep getting the current value of pointer (*s), and then moving the pointer one char forward (s++). This has the effect of marching well past the end of the string into "garbage" (uninitialized memory), which gets printed to the console as a result.
In addition to what everyone else said in regards to you ignoring the string terminal character and just printing willy-nilly what's in memory past the string, the reason why your command prompt is also "garbage" is that by printing a particular "unprintable" character, your terminal session was left in a strange character mode. (I don't know which character it is or what mode change it does, but maybe someone else can pipe in about it that knows better than I.)
You are just printing out what is in memory because your loop doesn't stop at the end of the string. Each random byte is interpreted as a character. It will seg fault when you reach the end of the memory page (and get into unreadable territory).
Expanding ever so slightly on the answers given here (which are all excellent) ... I ran into this more than once myself when I was just beginning with C, and it's an easy mistake to make.
A quick tweak to your while loop will fix it. Everyone else has given you the why, I'll hook you up with the how:
#include <stdio.h>
int main() {
char *s = "lolololololololol";
while (*s != '\0') {
printf("%c", *s);
s++;
}
}
Note that instead of an infinite loop (while(1)), we're doing a loop check to ensure that the pointer we're pulling isn't the null-terminator for the string, thus avoiding the overrun you're encountering.
If you're stuck absolutely needing while(1) (for example, if this is homework and the instructor wants you to use it), use the break keyword to exit the loop. The following code smells, at least to me, but it works:
#include <stdio.h>
int main() {
char *s = "lolololololololol";
while (1) {
if (*s == '\0')
break;
printf("%c", *s);
s++;
}
}
Both produce the same console output, with no line break at the end:
lolololololololol
Your loop doesn't terminate, so println prints whatever is in the memory after the text you write; eventually it will access memory it is not allowed to read, causing it to segfault.
You can change the loop as the others suggested, or you can take advantage of fact that in c, zero is false and null (which terminates all strings) is also zero, so you can construct the loop as:
while (*s) {
Rather than:
while (*s != '\0')
The first one may be more difficult to understand, but it does have the advantage of brevity so it is often used to save a bit of typing.
Also, you can usually get back to your command prompt by using the 'reset' command, typing blindly of course. (type Enter, reset, Enter)

Resources