Scanf for a word in C language - c

Hey I got this code where I need to scanf the input of the user (ANO/NE) and store this input into variable "odpoved". How to do that? What I have now looks like it is scanning just the first letter of the input.
char odpoved;
printf("Je vše v pořádku? (ANO/NE)");
scanf("%s", &odpoved);
if(odpoved == "ANO" || odpoved == "ano"){
printf("Super, díky mockrát");
}
else if(odpoved == "NE" || odpoved == "ne"){
printf("To mě mrzí, ale ani já nejsem dokonalý");
}
else{
printf("Promiň, ale zmátl jsi mě. Takovou odpověď neznám!!!");
return 0;
}

The first thing you should know about is that char is a data type consisting of 1 byte and is used to store a single character such as 'a', 'b', 1, 2 etc... there are 256 possible characters which are often represented by the ASCII table ( https://www.ascii-code.com/).
As odpoved is a string you need to make it type char* or equivalently char [] which is a pointer to the first char in the array (string) of characters. The last char in a string is always a terminator byte '\0' used to indicate the end of a string. The null terminator is automatically inserted when the speech marks are used e.g. "sometext" or when %s is used to get input.
The other mistake you have made is to compare strings with == or != signs. This will not work as the first characters will be compared with each other. Hence to compare the characters you will need to use strcmp function provided when the string.h library is included. There are many other useful string functions such as strlen which tell you the length of the string etc.

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];

How can I use scanf and if with strings? (Very basic)

I just had my first class in C programing at college and I did this:
#include <stdio.h>
int main()
{
char answer='x';
printf("Should the crocodile eat the man? y/n ");
scanf("%s",&answer);
printf("%s",& answer);
if(answer == 'y')
{printf("the man is dead");}
if(answer == 'n')
{printf("the man still alive ");}
}
How can I do the same with strings instead of single characters?
I have tried many things but nothing works.
In C, a string is a sequence of character values followed by a zero-valued terminator. The string "hello" is represented by the sequence {'h', 'e', 'l', 'l', 'o', 0}.
Strings are stored as arrays of char - the array must be large enough to hold the entire string plus the 0 terminator, so to store the string "hello", you need an array of char that's at least 6 elements long.
It's important to remember that an array of char doesn't have to contain a string - you can use it to store character data that's not meant to be interpreted as a string. You can also store more than one string to an array, like so:
/**
* Array size is determined by number of elements in the initializer
*/
char strs[] = {'T','h','i','s',0,'i','s',0,'a',0','t','e','s','t',0};
After this, strs will contain 4 strings: "This", "is", "a", "test".
So, to store the strings "y" or "n", you need an array of char that's at least 2 elements wide.
char answer[2];
To read strings with scanf, you use the %s conversion specifier:
scanf( "%s", answer );
%s tells scanf to skip over any leading whitespace, then read a sequence of non-whitespace characters and store them to the answer array. A 0 terminator will automatically be appended to the array, making it a string.
In this case, you don't need to use the & operator on answer; under most circumstances, an expression of type "array of T" will be converted ("decay") to an expression of type "pointer to T", so the expression answer "decays" from type char [2] to type char *.
To be safe, you should specify a maximum field width so that you don't read more characters than the target array is sized to hold:
scanf( "%1s", answer );
Since we have to reserve an element for the 0 terminator, the field width specifier should be at least 1 less than the size of the target array. Since our target array is sized to hold 2 elements, the field width specifier pretty much has to be 1.
To compare strings, use the strcmp or strncmp library functions:
if ( strcmp( answer, "y" ) == 0 )
{
// process "y" answer
}
Yes, strcmp returns 0 on a match.
You could also do a comparison against individual elements in the array:
if ( answer[0] == 'y' )
{
// process "y" answer
}
Remember
If you want to read a single character from the input stream and store it to a single character object with scanf, you would use the %c conversion specifier:
char answer; // single character, not an array
scanf( " %c", &answer ); // use & operator to obtain pointer, blank skips
// leading whitespace
If you want to read a sequence of non-whitespace characters from the input stream and store them to an array of char with scanf, you would use the %s conversion specifier:
char answer[2]; // array of character
scanf( "%1s", answer ); // do not use & operator to obtain pointer, array
// expressions are converted to pointer expressions
// automatically in this case.
You need to create a buffer to store the string:
char answer[50]; // change 50 to the maximum length of an answer + 1
scanf("%s", answer);
Yes but you need to pass it a buffer for the string and use strcmp instead of == for comparison.
#include <stdio.h>
#include <string.h>
int main()
{
char answer[16];
printf("Should the crocodile eat the man? yes/no ");
scanf("%15s", answer);
printf("%s", answer);
if (strncmp(answer, "yes", 16) == 0) {
printf("the man is dead\n");
} else if (strncmp(answer, "no", 16) == 0) {
printf("the man still alive\n");
}
}

How to change multicharacter signs by other ones in C?

I've got an UTF-8 text file containing several signs that i'd like to change by other ones (only those between |( and |) ), but the problem is that some of these signs are not considered as characters but as multi-character signs. (By this i mean they can't be put between '∞' but only like this "∞", so char * ?)
Here is my textfile :
Text : |(abc∞∪v=|)
For example :
∞ should be changed by ¤c
∪ by ¸!
= changed by "
So as some signs(∞ and ∪) are multicharacters, i decided to use fscanf to get all the text word by word. The problem with this method is that I have to put space between each character ... My file should look like this :
Text : |( a b c ∞ ∪ v = |)
fgetc can't be used because characters like ∞ can't be considered as one single character.If i use it I won't be able to strcmp a char with each sign (char * ), i tried to convert my char to char* but strcmp !=0.
Here is my code in C to help you understanding my problem :
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(void){
char *carac[]={"∞","=","∪"}; //array with our signs
FILE *flot,*flot3;
flot=fopen("fichierdeTest2.txt","r"); // input text file
flot3=fopen("resultat.txt","w"); //output file
int i=0,j=0;
char a[1024]; //array that will contain each read word.
while(!feof(flot))
{
fscanf(flot,"%s",&a[i]);
if (strstr(&a[i], "|(") != NULL){ // if the word read contains |( then j=1
j=1;
fprintf(flot3,"|(");
}
if (strcmp(&a[i], "|)") == 0)
j=0;
if(j==1) { //it means we are between |( and |) so the conversion can begin
if (strcmp(carac[0], &a[i]) == 0) { fprintf(flot3, "¤c"); }
else if (strcmp(carac[1], &a[i]) == 0) { fprintf(flot3,"\"" ); }
else if (strcmp(carac[2], &a[i]) == 0) { fprintf(flot3, " ¸!"); }
else fprintf(flot3,"%s",&a[i]); // when it's a letter, number or sign that doesn't need to be converted
}
else { // when we are not between |( and |) just copy the word to the output file with a space after it
fprintf(flot3, "%s", &a[i]);
fprintf(flot3, " ");
}
i++;
}
}
Thanks a lot for the future help !
EDIT : Every sign will be changed correctly if i put a space between each them but without ,it won't work, that's what i'm trying to solve.
First of all, get the terminology right. Proper terminology is a bit confusing, but at least other people will understand what you are talking about.
In C, char is the same as byte. However, a character is something abstract like ∞ or ¤ or c. One character may contain a few bytes (that is a few chars). Such characters are called multi-byte ones.
Converting a character to a sequence of bytes (encoding) is not trivial. Different systems do it differently; some use UTF-8, while others may use UTF-16 big-endian, UTF-16 little endian, a 8-bit codepage or any other encoding.
When your C program has something inside quotes, like "∞" - it's a C-string, that is, several bytes terminated by a zero byte. When your code uses strcmp to compare strings, it compares each byte of both strings, to make sure they are equal. So, if your source code and your input file use different encodings, the strings (byte sequences) won't match, even though you will see the same character when examining them!
So, to rule out any encoding mismatches, you might want to use a sequence of bytes instead of a character in your source code. For example, if you know that your input file uses the UTF-8 encoding:
char *carac[]={
"\xe2\x88\x9e", // ∞
"=",
"\xe2\x88\xaa"}; // ∪
Alternatively, make sure the encodings (of your source code and your program's input file) are the same.
Another, less subtle, problem: when comparing strings, you actually have a big string and a small string, and you want to check whether the big string starts with the small string. Here strcmp does the wrong thing! You must use strncmp here instead:
if (strncmp(carac[0], &a[i], strlen(carac[0])) == 0)
{
fprintf(flot3, "\xC2\xA4""c"); // ¤c
}
Another problem (actually, a major bug): the fscanf function reads a word (text delimited by spaces) from the input file. If you only examine the first byte in this word, the other bytes will not be processed. To fix, make a loop over all bytes:
fscanf(flot,"%s",a);
for (i = 0; a[i] != '\0'; )
{
if (strncmp(&a[i], "|(", 2)) // start pattern
{
now_replacing = 1;
i += 2;
continue;
}
if (now_replacing)
{
if (strncmp(&a[i], whatever, strlen(whatever)))
{
fprintf(...);
i += strlen(whatever);
}
}
else
{
fputc(a[i], output);
i += 1; // processed just one char
}
}
You're on the right track, but you need to look at characters differently than strings.
strcmp(carac[0], &a[i])
(Pretending i = 2) As you know this compares the string "∞" with &a[2]. But you forget that &a[2] is the address of the second character of the string, and strcmp works by scanning the entire string until it hits a null terminator. So "∞" actually ends up getting compared with "abc∞∪v=|)" because a is only null terminated at the very end.
What you should do is not use strings, but expand each character (8 bits) to a short (16 bits). And then you can compare them with your UTF-16 characters
if( 8734 = *((short *)&a[i])) { /* character is infinity */ }
The reason for that 8734 is because that's the UTF16 value of infinity.
VERY IMPORTANT NOTE:
Depending if your machine is big-endian or little-endian matters for this case. If 8734 (0x221E) does not work, give 7714 (0x1E22) a try.
Edit Something else I overlooked is you're scanning the entire string at once. "%s: String of characters. This will read subsequent characters until a whitespace is found (whitespace characters are considered to be blank, newline and tab)." (source)
//feof = false.
fscanf(flot,"%s",&a[i]);
//feof = ture.
That means you never actually iterate. You need to go back and rethink your scanning procedure.

How to add a character to the back of a char array when you obtain it with a gets() function in c?

I have an array of charracters where I put in information using a gets().
char inname[30];
gets(inname);
How can I add another character to this array without knowing the length of the string in c? (the part that are actual letters and not like empty memmory spaces of romething)
note: my buffer is long enough for what I want to ask the user (a filename, Probebly not many people have names longer that 29 characters)
Note that gets is prone to buffer overflow and should be avoided.
Reading a line of input:
char inname[30];
sscanf("%.*s", sizeof(inname), inname);
int len = strlen(inname);
// Remove trailing newline
if (len > 0 && inname[len-1] == '\n') {
len--;
inname[len] = '\0'
}
Appending to the string:
char *string_to_append = ".";
if (len + strlen(string_to_append) + 1) <= sizeof(inname)) {
// There is enough room to append the string
strcat(inname, string_to_append);
}
Optional way to append a single character to the string:
if (len < sizeof(inname) - 2) {
// There is room to add another character
inname[len++] = '.'; // Add a '.' character to the string.
inname[len] = '\0'; // Don't forget to nul-terminate
}
As you have asked in comment, to determine the string length you can directly use
strlen(inname);
OR
you can loop through string in a for loop until \0 is found.
Now after getting the length of prvious string you can append new string as
strcat(&inname[prevLength],"NEW STRING");
EDIT:
To find the Null Char you can write a for loop like this
for(int i =0;inname[i] != 0;i++)
{
//do nothing
}
Now you can use i direcly to copy any character at the end of string like:
inname[i] = Youe Char;
After this increment i and again copy Null char to(0) it.
P.S.
Any String in C end with a Null character termination. ASCII null char '\0' is equivalent to 0 in decimal.
You know that the final character of a C string is '\0', e.g. the array:
char foo[10]={"Hello"};
is equivalent to this array:
['H'] ['e'] ['l'] ['l'] ['0'] ['\0']
Thus you can iterate on the array until you find the '\0' character, and then you can substitute it with the character you want.
Alternatively you can use the function strcat of string.h library
Short answer is you can't.
In c you must know the length of the string to append char's to it, in other languages the same applies but it happens magically, and without a doubt, internally the same must be done.
c strings are defined as sequences of bytes terminated by a special byte, the nul character which has ascii code 0 and is represented by the character '\0' in c.
You must find this value to append characters before it, and then move it after the appended character, to illustrate this suppose you have
char hello[10] = "Hello";
then you want to append a '!' after the 'o' so you can just do this
size_t length;
length = strlen(hello);
/* move the '\0' one position after it's current position */
hello[length + 1] = hello[length];
hello[length] = '!';
now the string is "Hello!".
Of course, you should take car of hello being large enough to hold one extra character, that is also not automatic in c, which is one of the things I love about working with it because it gives you maximum flexibility.
You can of course use some available functions to achieve this without worrying about moving the '\0' for example, with
strcat(hello, "!");
you will achieve the same.
Both strlen() and strcat() are defined in string.h header.

How to replace a character in a string with NULL in ANSI C?

I want to replace all 'a' characters from a string in ANSI C. Here's my code:
#include <stdio.h>
#include <stdlib.h>
void sos(char *dst){
while(*dst){
if(*dst == 'a')
*dst = '\0';
dst++;
}
}
int main(void){
char str[20] = "pasternak";
sos(str);
printf("str2 = %s \n", str);
return 0;
}
When I run it, result is:
str2 = p
But it should be
str2 = psternk
It works fine with other characters like 'b' etc. I tried to assign NULL to *dst, but I got error during compile.
How can I remove 'a' characters now?
In C, strings are zero-terminated, it means that when there's a '\0' in the string it is the end of the string.
So what you're doing is spliting the string in 3 different ones:
p
stern
k
If you want to delete the a you must move all the characters after the a one position.
What printf does is: read bytes until a '\0' is found.
You transformed "pasternak" to "p\0astern\0k", so printf prints p.
This convention is used on the string functions of the stdlib so that you don't have to pass string length as an argument.
This is why it is said that in C strings are null terminated: it is just a convention followed by the C stdlib.
The downside, as you discovered, is that strings cannot contain \0.
If you really want to print a given number of bytes, use something like fwrite, which counts the number of bytes to be printed, so it can print a \0.
The answers previously provided are perfect to explain why your code does not work. But you can try to use strtok to split the string based on the 'a' characters, to then join the parts together or simply print them appart. Check this example: http://www.tutorialspoint.com/c_standard_library/c_function_strtok.htm
'\0' is how the C language tools recognize the end of the string. In order to actually remove a character, you'll need to shift all of the subsequent characters forward.
void sos(char *dst) {
int offset = 0;
do {
while (dst[offset] == 'a') ++offset;
*dst = dst[offset];
} while (*dst++);
}

Resources