I wrote the below function :
typedef enum {GREEN,BLACK, WHITE} color;
void StartGame(Piece board[8][8])
{
color currentPlayer=WHITE;
char location[2];
int gameover=1;
while(gameover)
{
printf("%d\n",currentPlayer);
if(currentPlayer==WHITE)
printf(BOLDWHITE"White: Please select a piece:\n");
else
printf(BOLDBLACK"Black: Please select a piece:\n");
printf("%d\n",currentPlayer);
scanf("%s",location);
printf("%d\n",currentPlayer);
if(currentPlayer==WHITE)
currentPlayer=BLACK;
else
currentPlayer=WHITE;
}
}
I print the currentPlayer on any level to see what's going on -> here what I get:
2
White: Please select a piece:
2
a1
0
2
White: Please select a piece:
2
Why the current player is 0 after scanf? I didn't touch it.
The buffer location has only room for 2 characters and scanf puts an extra NUL character at end. Therefore you have a stack corruption issue. Just give more room to location, for example:
char location[8];
EDIT
Since you just want to read a string, I recommend you using fgets, which allows you to limit the number of read characters from the input string. Thus, my code would look like this:
char location[8];
...
fgets(location, sizeof(location), stdin); //instead of scanf, fgets reads at most one less than buffer's size characters.
You only have to worry about the fact that fgets puts a final end line character (\n) at the end, but this should not be a deal if you just process the 2 first characters of the string.
It seems you overwrite the memory occupied by currentPlayer when you enter a string in character array location. As it seen from the console output you enetered string a1. That to store it in array location it shall be defined at leat as
char location[3];
because scanf appends entered strings with the terminating zero.
It would be better if you would use function fgets instead.
You should use something like this:
sprintf(format, "%%%dX", sizeof(buffer));
fscanf(file, format, &buffer);
Related
I compiled this code using gcc (tdm-1) 5.1.0 and please tell me why the output doesn't contain "hello"
#include<stdio.h>
void main()
{
int i;
char st[20];
printf("Enter a string ");
scanf("%s",st);
for(i=0;i<20;i++)
{
printf("%c",st[i]);
}
}
Input:hello
Output: # #
You print all 20 elements of the array, but if the user entered a string smaller than that not all elements would be initialized. They would be indeterminate and seemingly random.
Remember that char strings in C are really called null-terminated byte strings. That null-terminated bit is important, and mean you can easily find the end of the string by checking the current character agains '\0' (which is the terminator character).
Or you could just use the strlen function to get the length of the string instead:
for(i=0;i<strlen(st);i++) { ... }
Or use the "%s" format to print the string:
printf("%s", st);
Also note that without any protection the scanf function will allow you give longer input than is space for in the array, so you need to protect agains that, for example by limiting the amount of characters scanf will read:
scanf("%19s",st); // Write at most 19 character (*plus* terminator) to the string
Now for why your input doesn't seem to be printed, it's because the indeterminate contents of the uninitialized elements. While you're not going out of bounds of your array, you still go out of bounds of the actual string. Going out of bounds leads to undefined behavior.
What's probably is happening is that some of the "random" indeterminate contents happens to be a carriage return '\r', which moves the cursor to the start of the line and the output already written will be overwritten by the uninitialized elements in your array.
Here's a short example as Qubit already explained:
#include <stdio.h>
void main () {
char str1[20];
printf("Enter name: ");
scanf("%s", str1);
printf("Entered Name: %s", str1);
}
Here
char st[20];
st is a local variable & default array st contents are garbage not zero. So if you scan less than 20 characters into st, in that case remaining location of array st contains garbage, hence it's printing some junk data like # # in case of
char st[20];
printf("Enter a string ");
scanf("%s",st);
for(i=0;i<20;i++) {
printf("%c",st[i]);
}
& it's a bad practice as if user entered few char lets say 5 char, then your loop rotates 20 times, internally it will do more operations or consume more CPU cycle.
So if you want to print a char array char by char, then you should rotate a loop until \0 char encounters, for e.g
for(i=0;st[i];i++) { /* this fails when \0 encounters */
printf("%c",st[i]);
}
Or
as others suggested you can print char array st using single printf by using %s format specifier like
printf("%s\n",st); /*here printf starts printing from base address of st
and prints until \0 */
Also it's better to initialize char array st while declaring itself. for e.g
char st[20] ="";
I need to get a user-input string with a maximum length of 50 chars. Therefore I defined a MAX_STRING_LENGTH variable at 50 and the string is initalized with 51 characters. However, every time the input is greater than 48 characters, the string is cut from the last two characters. This is a school exercise and I can't use <string.h>.
#include <stdio.h>
#define MAX_STRING_LENGTH 50
int main(void)
{
int j=0;
char stringInput[MAX_STRING_LENGTH+1]; //string initialized.
printf("Please enter a valid string\n");
fgets(stringInput,MAX_STRING_LENGTH,stdin); //string input.
for(j=0;stringInput[j]!='\0';j++);
if(j<MAX_STRING_LENGTH+1)
{
j=j-1;
stringInput[j]='\0'; //remove newline if it exists
}
//...
return 0;
}
I don't understand why the string is losing 2 characters.
I am assuming that a newline(\n) is created always when using fgets (even if a full string of 50 characters is inputted), and I'm losing 1 character always(and therefore I have to increase the string size of the string). However I do not understand how the other character is lost.
I would appreciate your feedback. Thank you
In this call
fgets(stringInput,MAX_STRING_LENGTH,stdin);
you specified that at most MAX_STRING_LENGTH - 1 characters will be read in the array stringInput.
If you want that the array can contain a string with 50 characters (excluding the terminating zero) then you have to call fgets like
fgets(stringInput,MAX_STRING_LENGTH + 1,stdin);
But in this case the new line character that corresponds to the entered key Enter will still be in the input buffer if the user entered exactly 50 characters. To extract it you should declare the array at least like
char stringInput[MAX_STRING_LENGTH + 2];
and write the call like
fgets(stringInput,MAX_STRING_LENGTH + 2,stdin);
However it would be better initially to declare MAX_STRING_LENGTH equal to 52.
this little loop
for(j=0;stringInput[j]!='\0';j++);
if(j<MAX_STRING_LENGTH+1)
{
j=j-1;
stringInput[j]='\0'; //remove newline if it exists
}
removes the last character regardless of what it contains.
This is a [c] not a [c++] question.
Documentation for fgets
This is my target:
input: string with mixed ASCII characters (uppercase, lowercase, numbers, spaces)
output: string with only uppercase characters
I have this:
#include <stdio.h>
void csere(char s[]){
int i;
for(i=0; s[i]!='\0'; i++){
if('a'<=s[i] && s[i]<='z'){
s[i]-=32;
}
printf("%c", s[i]);
}
}
void main(){
char s[1];
scanf("%s", &s);
csere(s);
}
My problem is:
The function stops at the first 'space' character in the string.
I tried to change the s[i] != '\0' in the 'for' part for i <
strlen(s) or just for s[i], but I still get the same result.
Example: qwerty --> QWERTY, but qwe rty --> QWE
(smaller problem: The program only accepts strings with length less than 12, if i change the 1 to 0 in main function.)
Thanks for help. Sorry for bad English.
scanf only scans non-whitespace characters with the %s modifier. If you want to read everything on a string you should use fgets with stdin as the third parameter:
fgets(s, sizeof s, stdin);
If you really need to use scanf for homework or something, you should use something like:
scanf("%128[^\n]", s);
Also, take note you are not allocating enough space for the string, the fact that it has not crashed is just pure coincidence... you should allocate the space on your array:
char s[128]; // change 128 for max string size
Actually, the fgets() usage I wrote earlier would only read 1 character (including the terminator string) since you only put 1 character on the array... change the array size and it should work.
You could also just use toupper() on ctype.h, but I guess this is some kind of homework or practice.
Furthermore, if you are allowed to use pointers, this would be a shorter (and probably more performant although that'd have to be tested... compilers are good these days :-) ) way to convert to uppercase (notice though it changes your original char array, and doesn't print it, although that'd be easy to modify/add, I'll leave it to you):
void strupper(char *sptr) {
while (*sptr) {
if ((*sptr >= 'a' ) && (*sptr <= 'z')) *sptr -= 32;
sptr++;
}
}
From scanf
s
Matches a sequence of bytes that are not white-space characters. The application shall ensure that the corresponding argument is a pointer to the initial byte of an array of char, signed char, or unsigned char large enough to accept the sequence and a terminating null character code, which shall be added automatically.
This means, with %s, scanf reads a string until it encounters the first white space character. Therefore, your function converts the given string only to the first space.
To the second (smaller) problem, the array s must be large enough for the entire string given. Otherwise, you overwrite the stack space and get undefined behaviour. If you expect larger strings, you must increase the size of s, e.g.
char s[100];
While I could use strings, I would like to understand why this small example I'm working on behaves in this way, and how can I fix it ?
int ReadInput() {
char buffer [5];
printf("Number: ");
fgets(buffer,5,stdin);
return atoi(buffer);
}
void RunClient() {
int number;
int i = 5;
while (i != 0) {
number = ReadInput();
printf("Number is: %d\n",number);
i--;
}
}
This should, in theory or at least in my head, let me read 5 numbers from input (albeit overwriting them).
However this is not the case, it reads 0, no matter what.
I understand printf puts a \0 null terminator ... but I still think I should be able to either read the first number, not just have it by default 0. And I don't understand why the rest of the numbers are OK (not all 0).
CLARIFICATION: I can only read 4/5 numbers, first is always 0.
EDIT:
I've tested and it seems that this was causing the problem:
main.cpp
scanf("%s",&cmd);
if (strcmp(cmd, "client") == 0 || strcmp(cmd, "Client") == 0)
RunClient();
somehow.
EDIT:
Here is the code if someone wishes to compile. I still don't know how to fix
http://pastebin.com/8t8j63vj
FINAL EDIT:
Could not get rid of the error. Decided to simply add #ReadInput
int ReadInput(BOOL check) {
...
if (check)
printf ("Number: ");
...
# RunClient()
void RunClient() {
...
ReadInput(FALSE); // a pseudo - buffer flush. Not really but I ignore
while (...) { // line with garbage data
number = ReadInput(TRUE);
...
}
And call it a day.
fgets reads the input as well as the newline character. So when you input a number, it's like: 123\n.
atoi doesn't report errors when the conversion fails.
Remove the newline character from the buffer:
buf[5];
size_t length = strlen(buffer);
buffer[length - 1]=0;
Then use strtol to convert the string into number which provides better error detection when the conversion fails.
char * fgets ( char * str, int num, FILE * stream );
Get string from stream.
Reads characters from stream and stores them as a C string into str until (num-1) characters have been read or either a newline or the end-of-file is reached, whichever happens first.
A newline character makes fgets stop reading, but it is considered a valid character by the function and included in the string copied to str. (This means that you carry \n)
A terminating null character is automatically appended after the characters copied to str.
Notice that fgets is quite different from gets: not only fgets accepts a stream argument, but also allows to specify the maximum size of str and includes in the string any ending newline character.
PD: Try to have a larger buffer.
I have a file which contains several lines.
I am tokenizing the file, and if the token contains contains .word, I would like to store the rest of the line in c-string.
So if:
array: .word 0:10
I would like to store 0:10 in a c-string.
I am doing the following:
if (strstr(token, ".word")) {
char data_line[MAX_LINE_LENGTH + 1];
int word_ret = fgets(data_line, MAX_LINE_LENGTH, fptr);
printf(".word is %s\n", data_line);
}
The problem with this is that fgets() grabs the next line. How would I grab the remainder of the current line? Is that possible?
Thank you,
strstr() returns a pointer to where the first character of ":word" is found.
This means that if you add the length of ":word" (5 characters) to that, you will get a pointer to the characters after ":word", which is the string you want.
char *x = strstr(token, ".word");
char *string_wanted = x + 5;
First of all it is obvious that you need to use fgets only once for every line you parse and then work with a buffer where the line is stored.
Next having a whole line you have several choices: if the string format is fixed (something like " .word") then you may use the result of "strstr" function to locate the start of ".word", advance 6 characters (including space) from it and print the required word from the found position.
Another option is more complex but in fact is a liitle bit better. It is using "strtok" function.
You need to have already read the input into a buffer, which I'm assuming is token, and from there you just copy from the return value of strstr + the length of ".word" to the end of the buffer. This is what I'd do:
char *location = strstr(token, ".word");
if (location != NULL) {
char data_line[MAX_LINE_LENGTH];
strncpy(data_line, location + 5, MAX_LINE_LENGTH);
printf(".word is %s\n", data_line);
}
You could add 5 or 6 to the pointer location (depending on whether or not there's going to be a space after ".word") to get the rest of the line.
Also note that the size parameter in strncpy and fgets includes space for the terminating NUL character.