hello ive got this simple program, where i need to imput a number, and 2-letter string, the string is working normally, but the number gets weird
here is the program
void main(){
int input_year=0;
char input_string[1];
scanf("%d %s", &input_year, input_string);
char temp1 = input_string[0];
char temp2 = input_string[1];
printf("%d", input_year);
printf("%c", temp1);
printf("%c", temp2);
}
input used: 20200405 RD number (whitespace) String
the temp1 and temp2 are ok, and do what i expect them to do, but the input_year prints 20200192 rather than 20200405.
You need to remember that strings in C are really called null-terminated strings. A string of even one single character need space for two characters to fit the null-terminator.
Also remember that the size provided in array declarations is the actual number of elements, not the top index. So when you define input_string as an array of a single element, that means it only have a single element, with index 0.
If you want to read a string containing two characters you need to define an array of three characters: The two characters in the string plus the null-terminator.
You also need to limit the number of characters that scanf will read, so users can't input arbitrarily long strings and cause buffer overflows.
In short:
// Place for two characters, plus null-terminator
char input_string[3];
// Limit the input to only two characters (not including null-terminator)
scanf("%d %2s", &input_year, input_string);
On another note, if you want to use the date input in any other way than a single number, I recommend you read it as separate year, month and day:
unsigned year, month, day;
char input_string[3];
scanf("%4u%u%2u %2s", &year, &month, &day, input_string);
Also note that I use unsigned as a type (and the corresponding scanf format) as the input can't and shouldn't be negative.
You should also really check what scanf returns, to make sure the input is valid.
And lastly, to better handle input validation, I recommend you use fgets to read the input into a large string. Then use e.g. sscanf (with checking return values) to attempt to parse the input.
Your input buffer is too small
char input_string[1];
That reserves space for one character. You need 3 in your case of 'rd'. The extra one is because c always adds a 0 at the end of a string. So you need
char input_string[3];
at least if you are sure its always 2 characters
Or maybe
char input_string[10];
if it could be larger. You can tell sprintf the max size you will accept like this (say 2 in your case)
scanf("%d %2s", &input_year, input_string);
-----------^
Related
I'm new to this, and I'm assuming there is an easy solution to my issue. My first formula works exactly how I'd like it to. If the user input matches dogage99, then it prints "Correct". I want to do something similar, but using words instead of numbers. I've switched double for char, and adjusted the formula accordingly.
The problem is, the second formula doesn't work as I expected. When the user input matches dogname1, it doesn't print "Correct", it just continuously asks to "enter dog name".
What can I do to fix my issue?
int main()
{
double guess99;
double dogage99 = 3;
while (guess99 != dogage99) {
printf ("enter dog age:");
scanf ("%lf", &guess99);
}
printf ("Correct\n");
char guess1;
char dogname1= "spot";
while (guess1 != dogname1) {
printf ("enter dog name:");
scanf ("%s", &dogname1);
}
printf ("Correct\n");
First of all the line
char dogname1= "spot";
should be corrected to
char *dogname1= "spot";
This way the char array dogname1 will be correctly initialized as a character array and will contain the null-terminator "\0" at the end of the array.
You must also ensure, that guess has enough memory secured, so you must either create a array of sufficiently enough bytes (for e.g. 256), or dynamically allocate memory. In this example I would do the first changing char guess1; to char guess1[256];
Knowing that guess1 has sufficiently enough memory and a null-terminator we can next rewrite the while loop to
while(strcmp(guess1, dogname1)) { ... }
The strcmp() standard library function returns 0 if and only if both character arrays match lexicographical and that is also the time we want to go out of the loop. It is also important to know, that you must ensure both arrays have null-terminators when using this exact function. If you cannot ensure it, then use strncmp().
For reference about all the different compare functions and their implications: https://www.ibm.com/docs/en/aix/7.1?topic=s-strcmp-strncmp-strcasecmp-strcasecmp-l-strncasecmp-strncasecmp-l-strcoll-strcoll-l-subroutine
I am sure the compiler is complaining big time at you about
char dogname = "spot";
in c the type char represent a single character not a string. Strings in C are a sequnce of characters followed by a char set to \0. The compiler will set that up for you if you do
char *dogname="spot";
It will allocate 5 bytes , load s,p,o,t,\0 into those bytes and set the dogname variable to point at the first character.
If you want to compare string you have to use the c library function called strcmp - https://man7.org/linux/man-pages/man3/strcmp.3.html.
Alos you need a char array to receive the input. We just say we want 50 characters. Must also tell scanf to not allow more than 50 charaters. Note that I asked for 51 character array to allow for the trailing 0 that must always be present.
so your loop becomes
char guess1[51];
char *dogname1= "spot";
while (guess1 != dogname1) {
printf ("enter dog name:");
scanf ("%50s", guess1);
}
printf ("Correct\n");
note you must #include string.h
check this out https://www.tutorialspoint.com/cprogramming/c_strings.htm
This is the code I have written.
#include<stdio.h>
int main()
{
char playerName;
int gameScores [10]= {12,5,21,15,32,10};
int totalPoints=0;
int x;
float avg;
for (playerName='A'; playerName<='Z'; playerName=playerName+1)
{
print("%c",playerName);
scanf ("/%s",playerName[x]);
}
putchar('\n');
for(x=6; x<10; x++)
{
printf ("What did the player score in game %d?". x+1);
scanf ("%d", &gameScores [x]);
}
for(x=0; x<10; x++)
{
totalPoints +=gamesScores[x];
}
avg=((float) totalPoints/10);
printf("\n\nThe Play's scoring average is %.1f.\n", avg);
return (0)
}
I am running into problems around line 22 with
scanf("/%s",playerName [x]);
it keeps coming up with an error. It says that the subscripted value is not an array, pointer, or vector. I would like it to list the player's name before the score average. Without the scanf if just gives me the alphabet above the input not a players name.
char playerName is just a single char, one byte. C strings are arrays of char, terminated by a zero (NUL) character. The single character treated as a string could therefore only hold the terminating NUL, and nothing else, i.e., it can only be the empty string.
You need to define playerName as an array large enough to hold the name + the terminating NUL, e.g.,:
#define MAX_NAME_LENGTH 100
char playerName[MAX_NAME_LENGTH + 1];
This would suffice for a single name, but since you have multiple players, you need an array of these arrays, e.g.:
#define MAX_PLAYERS 10
#define MAX_NAME_LENGTH 100
char playerName[MAX_PLAYERS][MAX_NAME_LENGTH + 1];
(You can also allocate the memory dynamically, such as with malloc, but that's outside the scope of the question.)
Also, your scanf has an extra slash / in the format string, which causes it to fail unless each player name is preceded by a slash in the input, which I'm guessing is not the case. Maybe you were going for the backslash \ to escape the %, but that is also not required here since the percent sign is only "special" in the printf/scanf format strings, not in C itself.
In a proper program you also need to guard against buffer overflow when reading with scanf. And should check the return value of scanf to verify that the input was successfully read (and perhaps retry or abort the program if not). See the documentation of scanf (and every other function you use) for the return values and arguments.
(Overall I would suggest learning to read lines into a buffer with fgets, as it may often be hard to recover from scanf errors in a sensible way, especially when the format strings become more complicated.)
I have a program to do basic things with two char arrays. Everything works fine when the size limit of the first is equal to size limit of the second, but when the size of the first char array is different to the size of the other, the program starts to read/write the strings in a strange way.
For example, if the limit of the first is 31 and the limit of the other is 5, if the typed characters in the first are more than 8 or something like that the program won't let the user typed anything on the second array as if it was full already.
I tried to fix it without using the functions of string.h, but the programs still did the same when the size limit of the two char arrays were different.
#include <stdio.h>
#include <string.h>
#define LIMIT1 31
#define LIMIT2 5
/*Function: void copy_string(char *pointer_destination, char *pointer_source)
Precondition: it needs a pointer to the direction of memory of the first element of two char vectors and the size limit of the 'destination' vector
Postcondition: it puts all the elements of the 'source' vector into the other until the last element that */
void copy_string(char *pointer_destination, char *pointer_source, int LIMd){
//Variable declaration
int i = 0;
/*Cycle for replacing the element of the 'destination' vector by the element of the 'source' vector.
When the element of the 'destination' OR of the 'source' is the null character, this cycle ends*/
for(; i < LIMd && *(pointer_source + i) != '\0'; i++){
*(pointer_destination + i) = *(pointer_source + i);
}
*(pointer_destination + i) = '\0';
}
int main(){
//Variable declaration
int restart;
char username[LIMIT1], string2[LIMIT2];//Here we define the limit for obvious reasons
//Restart cycle starts here
do{
//Data input
printf("Type your username (maximum 30 characters)\n");
fgets(username, LIMIT1 - 1, stdin);
fflush(stdin);
printf("Type a string of maximum 30 characters\n");
fgets(string2, LIMIT2 - 1, stdin);
fflush(stdin);
printf("Your typed username and your typed second string are, respectively:\n");
fputs(username, stdout);
fputs(string2, stdout);
printf("Concatenating, the username is now\n");
strcat(username, string2);
fputs(username, stdout);
printf("Now I'll copy what is in your username and I'll put it in the second string,\n");
copy_string(string2, username, LIMIT2 - 1);
fputs(string2, stdout);
//Restart cycle switch
printf("Type '0' to close this program, otherwise it'll restart itself\n");
scanf("%d", &restart);
fflush(stdin);
//Restart cycle ends here
}while(restart);
return 0;
}
I expected that if the size of the two arrays were different, the program would still read and write them properly (if the size of the first is 3, read from the user only the first three characters and put behing a \0 and if the size of the other is 25 do the same but with 25 as the size limit)
You're not very specific about your actual and expected output, but I imagine it's this:
Steps to reproduce:
Run the program as posted
Get the prompt Type your username (maximum 30 characters)
Enter this is an especially long string
Expected result:
A prompt that says Type a string of maximum 30 characters and lets you enter a new string
Actual result:
Type a string of maximum 30 characters is written to screen but the program continues immediately without letting you enter another string.
This happens because the first fgets is set up to read no more than 30 characters from the user. If you enter more, it will only consume the first 30.
The next fgets will then consume the remainder of that line instead of a new line, giving the appearance of skipping the prompt.
You should use a large enough buffer to accomodate the line, so that this is not an issue. Alternatively, you can manually read and discard one character at a time until you find a \n, effectively draining stdin of the rest of the line.
You seem to be relying on fflush(stdin) to clear any unread input. This is undefined behaviour in standard C, and only works on some platforms as a non-standard extension. I suspect it doesn't work on yours, and either breaks input altogether or does nothing and causes the next fgets to read the rest of the input intended for the previous one.
Instead of fflush, you can check whether the string read by fgets ends in a newline ('\n', which you probably want to remove if it is there). If not, keep reading (and discarding) input until either a newline '\n' or EOF is encountered.
(In general I would also recommend not using scanf for user input - it's a lot easier to read into a temporary buffer with fgets and parse that with sscanf as needed.)
Another obvious, but unrelated, problem is strcat(username, string2); – this may exceed the length of username. You need to leave at least LIMIT2 - 1 extra space (that you don't allow fgets to use), or simply allocate a new array of the correct size after you know the lengths of each.
Warning fgets will save the \n if there is enough place to save it, I think your problem comes because in your examples the end of line is saved at least in the usename. So you need to remove it if present.
Warning you give the size minus 1 to fgets, but fgets already read the given length minus 1 to have place to put the null character at the end.
Note the message to read the second string is wrong because it indicates a length 30 rather than 4.
I've literally just started programming in C. Coming from a little understanding of Python.
Just had a lecture on C, the lecture was about this:
#include <stdio.h>
int main() {
FILE *file;
char name[10], degree[5];
int mark;
file = fopen("file.txt", "r");
while (fscan(file("%s %s %d", name, degree, &mark) != EOF);
printf("%s %s %d", name, degree, mark);
fclose(file);
}
I'm specifically asking why we the lecturer would have used an array rather than just declaring two string variables. Searching for a deeper answer than just, "that's just C for you".
There are multiple typos on this line:
while (fscan(file("%s %s %d", name, degree, &mark) != EOF);
printf("%s %s %d", name, degree, mark);
It should read:
while (fscanf(file, "%s %s %d", name, degree, &mark) == 3)
printf("%s %s %d", name, degree, mark);
Can you spot the 4 mistakes?
The function is called fscanf
file is an argument followed by ,, not a function name followed by (
you should keep looping for as long as fscanf converts 3 values. If conversion fails, for example because the third field is not a number, it will return a short count, not necessarily EOF.
you typed an extra ; after the condition. This is parsed as an empty statement: the loop keeps reading until end of file, doing nothing, and finally executes printf just once, with potentially invalid arguments.
The programmer uses char arrays and passes their address to fscanf. If he had used pointers (char *), he would have needed to allocate memory to make them point to something and pass their values to fscanf, a different approach that is not needed for fixed array sizes.
Note that the code should prevent potential buffer overflows by specifying the maximum number of characters to store into the arrays:
while (fscanf(file, "%9s %4s %d", name, degree, &mark) == 3) {
printf("%s %s %d", name, degree, mark);
}
Note also that these hard-coded numbers must match the array sizes minus 1, an there is no direct way to pass the array sizes to fscanf(), a common source of bugs when the code is modified. This function has many quirks and shortcomings, use with extreme care.
Take name[] for example. It's an array of chars, a collection of chars if you like.
There is no string type in c, so we use an array an array of chars when we want to use a string.
The code is written as such, so that we can read the actual string in a line of the file, in our array.
As a side note, this program will produce syntax errors.
What you have in every non-empty file is a series of bytes. Therefor, what your C program has to do is read bytes. Since the variable type char is used to represent a byte, and since you want to read multiple bytes at once for efficiency purposes, you read an array of chars. That's for the general understanding of what reading from a file means.
Going back to your example, there is no string type in C. A string is an array of bytes (char[]) ended by a nul character.
What the lecturer is doing is:
define an array of chars (which will contain a string) => char name[10] is an array that may contain a string of at most 9 characters (the last byte would be used for '\0').
ask fscanf to read a string, which means it will read multiple bytes (multiple chars) until it finds a nul character ('\0') and put all of that in the given array.
To understand what's happening, forget about string as an opaque data type (which might be true in other programming languages) and see them as what they really are: arrays of chars.
i have a given Input of four scanf-strings which i want to save in a multidimensional array. I Don't know if i save the string right, but i can't just simply print the whole array or certain characters of it.
char getr[4][4];
for (z=0; z<4; z++){
scanf(" %99s", &getr[z]);
}
for (s=0; s<4; s++) {
printf("%s\n",getr[s]);
}
Input:
abcd
efgh
ijkl
mnop
Output:
abcdefghijklmnop
efghijklmnop
ijklmnop
mnop
what if i just want to print the second line or the fourth character of the first line? Does anybody know?
First, change as following:
scanf(" %99s", getr[z]); //getr[z] is the address to take the 4 characters string
To print out the second line:
printf("%s\n", getr[1]);
To print out the fourth character of the first line:
printf("%c\n", getr[0][3]); // %c is used here because just print one character.
To store 4-char strings, like your example input, you need 5-char arrays to leave room for the terminating null character:
char getr[4][5];
Your scanf() format string should also reflect the amount of space you have; %99s could read up to 100 bytes (99 chars plus the null), and you only have 5 (including the null, after the above change). Also, &getr[z] and getr[z] happen to give the same address, but the types of the pointers are different -- but getr[z] gives a char * which is appropriate in this case. So...
scanf(" %4s", getr[z]);
Those changes will already keep the strings from running together, so individual strings can be accessed as getr[0] through getr[3]. To print individual characters within a string, add an additional set of indexing brackets and use a function that prints a character rather than a string:
fputc(getr[0][2],stdout); /* print 3rd char in 1st string */
printf("%c",getr[1][3]); /* print 4th char of 2nd string */
The reason you were getting all your strings concatenated was because the null char from the earlier strings overflowed into the next char array, and was overwritten by the first char of the next string you read. The last string's null would have overflowed past your whole 2D array into whatever was next in memory (which is bad).