I want to ask how can I scanf a letter that has value 0x00 (I know its null). I call my function echo -e '\x00' | function /.myfunction and I need to scanf it into a string for fprinting it later.
how can I scanf a letter that has value 0x00
Sure, with input Null Character1 Enter. "%s" treats a null character like any other non-white-space character.
char s[2];
scanf("%1s", s);
will nicely make s[0] == '\0' (due to input null character) and s[1] == '\0' due to the appended null character.
Subsequent code will likely have trouble working with s[] as a string though. You may want a new approach with "%c" or getchar(). Suggest an array of characters with an accompanying length, rather than a string.
If required to use scanf(), then keep track of the length with "%n".
char buf[100];
int n1,n2
if (scanf(" %n%99s%n2", &n1, buf, &n2) == 1) {
int length_read = n2 - n1;
for (int i=0; i<length_read; i++) {
if (isprint((unsigned char) buf[i])) {
printf("%c", buf[i]);
} else {
// do something special for non-printable characters.
printf("(%X)", (unsigned char) buf[i]);
}
}
}
1 Null Character may be difficult to enter directly other than piping as OP is using. Some keyboards allow Crtl Shift #.
Related
Please ignore the Japanese there.
I attempt to count the length of the string entered from stdin using the following code. But it didn't work expectedly:
#include <stdio.h>
int main(int argc, const char *argv[]) {
char str[100];
printf("文字列を入力してください:"); // Please enter a string:
fgets(str,99,stdin);
int n = 0;
while (str[n++] != '\0');
printf("文字列の長さは%dです\n", n); // The length of the string is %d\n
return 0;
}
For example, if I enter glacious, I'll get n=10, which I expected to be n=8.
I understand that n++ will increment n after str[n++] != '\0' gets evaluated, and \0 is the default character appended to every string. But somehow this doesn't make sense to me. I know I can make this work for my purpose by adding n-=2 at the end, but I really want to understand what's going on here. Many thanks in advance!
"I attempt to count the length of the string entered from stdin"..."I know I can make this work for my purpose by adding n-=2 at the end, but I really want to understand what's going on here. "
Documentation for fgets() includes the following:
"...reads a line from the specified stream and stores it into the string pointed to by str. It stops when either (n-1) characters are
read, the newline character is read, or the end-of-file is reached,
whichever comes first."
This call, without checking the return value of the function, and by passing an incorrect value for the length of the string, limits the potential of detecting errors, and introduces the possibility of undefined behavior. To address these issues, change this:
fgets(str,99,stdin);
To, for example this:
if( fgets (str, sizeof str, stdin) != NULL )
{
...
Dissecting the following: given user input value: "glacious", str looks like this in memory:
|g|l|a|c|i|o|u|s|\n|\0|?|...|?|
0 1 2 3 4 5 6 7 8 9 10 99
int n = 0;
while(str[n++] != '\0');
iterations:
n at start n at finish
1st: n==0, str[0] (g) != \0, n++, n==1
2nd: n==1, str[1] (l) != \0, n++, n==2
3rd: n==2, str[2] (a) != \0, n++, n==3
4th: n==3, str[3] (c) != \0, n++, n==4
5th: n==4, str[4] (i) != \0, n++, n==5
6th: n==5, str[5] (o) != \0, n++, n==6
7th: n==6, str[6] (u) != \0, n++, n==7
8th: n==7, str[7] (s) != \0, n++, n==8
9th: n==8, str[8] (\n) != \0, n++, n==9
10th: n==9, str[9] (\0) == \0, n++, n==10
Clearly illustrates the state of all iterations, including the final post-increment of n, bringing it's total to 10 for a user input assumed to be only 8 characters. The \n and the final post-increment ( for \0) account for the additional value to n`. In summary the problem is simply adjusting your expectations to account for all characters in the buffer, including the ones you do not see.
Of interest, counting value of n does not equate to measuring the string length of str, for which the idiomatic method ( strlen() ), will yield 9. Given the definition of a C string, the following shows varying results for each corresponding method of looking at str, assuming initialization:
char str[100] = {0};
And str contents are: "glacious\n"//null terminator is implied
//method to calculate n in discussion above
// //yields n == 10
int len = strlen(str); //yields n == 9
//after using strcspn()
str[strcspn(str, "\n")] = 0;
len = strlen(str); //yields n == 8
size_t size = sizeof str; //yields size == 100
As an aside, if goal is to count the number of entries, and if an alternative approach is okay, consider simplifying the method...
Replacing this section:
char str[100];
printf("文字列を入力してください:");
fgets(str,99,stdin);
int n = 0;
while(str[n++] != '\0');
printf("文字列の長さは%dです\n", n);
return 0;
With this one which will break the loop upon seeing \n (newline character), or EOF (-1) (#define in stdio.h), resulting in a correct count of user inputs (minus newline):
int count = 0;
printf("Please enter a string:");
int c = fgetc(stdin);
while(( c != '\n') && (c != EOF))
{
count++; //only increments when c meets criteria
fputc(c, stdout);
c = fgetc(stdin);
}
printf("\n\nThe length of the string is: %d\n", count);
return 0;
If fgets() encounters a newline character in stdin, it will write it to the end of str before the null terminator, and because you're using a post-increment operator in the condition expression of your while loop, you are also including the null terminator in your total count. This accounts for the difference of 2 from your expected value n.
Consider using strcspn(), found in the <string.h> header, so that you can compute the length of str up until the first encountered \n, or until the null terminator if none is found:
size_t n = strcspn(str, "\n");
The loop while(str[n++] != '\0'); counts all bytes read by fgets(), including the newline and the null terminator because n is incremented at every test including the last one that evaluates to false.
Also note that fgets(str, 99, stdin); should be fgets(str, 100, stdin); or better if (fgets(str, sizeof str, stdin) == NULL) return 1; to avoid undefined behavior in case of unexpected end of file (empty file redirected as input stream).
Modified version:
#include <stdio.h>
#include <string.h>
int main(int argc, const char *argv[]) {
char str[100];
printf("文字列を入力してください:"); // Please enter a string:
if (!fgets(str, sizeof str, stdin))
return 1;
str[strcspn(str, "\n")] = '\0'; // strip the trailing newline if any
int n;
for (n = 0; str[n] != '\0'; n++)
continue;
printf("文字列の長さは%dです\n", n); // The length of the string is %d\n
return 0;
}
This question already has an answer here:
fgets is getting skipped
(1 answer)
Closed 4 years ago.
Been trying to remove a character but the call to fgets gets skipped/jumped over. On different computers it runs like it should but for some reason, it skips and basically jumps to the end of the program. Any ideas?
Several problems in your code but I do not see any reason of fgets() skipped or jumped over. The getchar() function reads the next character from stdin. Generally when we give input to the getchar() function, we enter the character and press ENTER key. This left the \n character in input stream which can be consumed by next input function called. But in your case you are not calling any other input function after getchar().
[Try calling getchar() above fgets() and give input as - enter a character followed by ENTER key. You will see the fgets() is skipped because it consumes the leftover \n character from input stream stdin.]
Problem 1:
Look at this statement:
str[j] = str + 1;
Since, the str is a char array, str[j] represents a character at location j and str + 1 is pointer. So, this assignment is incompatible because you are trying to assign a char * type to a char. It should be:
str[j] = str[j + 1];
Problem 2:
Your code is having a logical problem. It is unable to handle the scenario where the character to be removed occurs consecutively in the input string. Test your code for input like "Hello World" [character l is occurring consecutively]. Your program output will be [after fixing problem 1]:
Enter a sentence:
Hello World
This is the sentence: Hello World
Enter character to remove:
l
Sentence after removal: Helo Word <==== character l not removed
Your program is unable to handle this particular scenario because once it removes a character, in the next iteration it starts with next character.
Problem 3:
The strlen() return type is size_t and you are using char type to receive its return value. Instead, you should use size_t type.
The getchar() return type is int [because it returns the special value EOF when the end of the input stream is reached]. You are using char type variable to receive getchar() return value.
One more point (it is not a problem but you should be aware of it and take the precautionary measures):
From fgets() [emphasis mine]:
Reads at most count - 1 characters from the given file stream and stores them in the character array pointed to by str. Parsing stops if end-of-file occurs or a newline character is found, in which case str will contain that newline character. If no errors occur, writes a null character at the position immediately after the last character written to str.
So, it is possible that your input buffer passed to fgets() can have new line character ('\n') in it. For e.g., if you give input Hello World followed by ENTER key than the input buffer str will have "Hello World\n" in it. In your case this will not cause any problem but few extra iteration of loop. You can remove the \n from str buffer like this:
fgets(str, 100, stdin);
str[strcspn(str, "\n")] = 0; // This will remove the trailing newline character from input buffer
Also, you should check the fgets() return. In case of failure, fgets() returns NULL.
Putting these altogether, you can do:
#include <stdio.h>
#include <string.h>
int main() {
char str[100];
size_t i, j, len;
int r;
printf("Enter a sentence: \n");
if (fgets(str, 100, stdin) == NULL) {
fprintf (stderr, ("fgets failed"));
return -1;
}
str[strcspn(str, "\n")] = 0;
printf("This is the sentence: %s\n", str);
printf("Enter character to remove: \n");
r = getchar();
/*If getchar returns EOF, no need to go through character removal logic*/
if (r != EOF) {
len = strlen(str);
i = 0;
while (str[i] != '\0') {
if (str[i] == (char)r) {
for (j = i; j < len; j++) {
str[j] = str[j+1];
}
len--;
}
else
i++;
}
}
printf("Sentence after removal: %s\n", str);
return 0;
}
Output:
# ./a.out
Enter a sentence:
Hello World
This is the sentence: Hello World
Enter character to remove:
l
Sentence after removal: Heo Word
# ./a.out
Enter a sentence:
zzzzz
This is the sentence: zzzzz
Enter character to remove:
z
Sentence after removal:
# ./a.out
Enter a sentence:
aazz
This is the sentence: aazz
Enter character to remove:
a
Sentence after removal: zz
Try changing r = getchar(); with scanf("%c\n", &r);.
Also, your loop has some bugs or inconsistencies:
You're assigning to str[j] the value of a pointer. Should be assigning to str[j] the value of str[j+1].
The end of the inner loop should be len-1 then.
j-- has no effect at all.
You should end your string with \0 after you're done, otherwise you'll print garbage (in my case it was a bunch of \ns).
Putting everything together:
for (i = 0; i < len; i++) {
if (str[i] == r) {
for (j = i; j < len-1; j++) {
str[j] = str[j+1];
}
len--;
}
}
str[len] = '\0';
printf("Sentence after removal: %s\n", str);
If you want to remove the \n at the end of the string after you read it, you can do
str[len] = '\0';
len--;
before the loop.
I'm making a program in which i ask for the username name, and i'd like to only accept strings with valid characters only (alphabetic).
I found that i can either use
do{
//since scanf returns the number of currectly input
if(scanf("%s", &name) == 1)
break;
else printf("Please enter a valid name.\n);
}while(1);
or
do{
check = 0;
scanf("%s", &name);
for(i=0; i<strlen(name; i++){
//since isalpha() returns != 0 if it's a letter
if(isalpha(name[i]) == 0){
printf("Invalid character. Please enter a valid name.\n");
check = 1;
break;
}
}
}while(check == 1);
But i'm not sure if any of those work, and what would be better to check if there isn't anything except alphabetic letters.
Also though about making all input letters (after this verification) on lower case and make the first letter upper case with
//all to lower except the first letter
for(i=1; i<strlen(name); i++){
name[i] = tolower(name[i]);
}
//first letter to upper
name[0] = toupper(name[i]);
x=1;
while(name[x] != '\0'){
//if the letter before is a white space, even the first letter, it should place the first letter of a name upper
if(name[x-1] == ' ')
name[x] = toupper(name[x]);
x++;
}
Would this work?
if(scanf("%s", &name) reads in all non-white-space, not just letters, into name and does not return if input is only "\n".
if(isalpha(name[i]) == 0){ loop is not bad, but scanf("%s", &name) still does not return if input is only "\n" or just white-space.
for(i=1; i<strlen(name); i++) name[i] = tolower(name[i]) works to make all following letters lower case, but if inefficient as code repeatedly calculates the string length.
Separate reading data and parsing data. Use fgets() to read the data and various code to test the data for correctness.
char buf[200];
fgets(buf, sizeof buf, stdin);
int n = 0;
// Skip leading white-space
// Look for A-Z, a-z or space (like a space between first & last)
// Skip white-space like \n
// Save into 'n' the current scan position
sscanf(buf, " %*[A-Za-z ] %n", &n);
if (n > 0 && buf[n] == '\0') Success(); // #user3121023
Should code need to rid buf of a potential trailing "\n", suggest:
buf[strcspn(buf, "\n")] = 0;
Let's look at each option.
First option:
do {
//since scanf returns the number of currectly input
if(scanf("%s", &name) == 1)
break;
else printf("Please enter a valid name.\n");
} while(1);
This won't quite work the way you expect. First off, what exactly is name? I'm almost sure that you want scanf("%s", name) instead (name instead of &name), unless you declared it as char name;, which would be catastrophic anyway.
Anyway, the problem I see with this approach is that you don't really validate the string. Read the man page section about %s:
s - Matches a sequence of non-white-space characters; the next pointer
must be a pointer to character array that is long enough to hold
the input sequence and the terminating null byte ('\0'), which is
added automatically. The input string stops at white space or at the
maximum field width, whichever occurs first.
Nothing says that the string is composed of alphabetic characters only.
Second option:
do{
check = 0;
scanf("%s", &name);
for(i=0; i<strlen(name); i++){
//since isalpha() returns != 0 if it's a letter
if(isalpha(name[i]) == 0){
printf("Invalid character. Please enter a valid name.\n");
check = 1;
break;
}
}
}while(check == 1);
Again, you probably want name rather than &name. You also shouldn't be calling strlen() in the for loop condition, because it's inefficient (strlen() is O(n)). A smart compiler may optimize it away, but it's hard for the compiler to know when it is safe to do so. Just call strlen() before the loop and store the result in a variable.
isalpha() expects an integer as an argument, which is expected to be either EOF or an unsigned char converted to int. Again, you don't show the declaration for name, but assuming that it is a character array, you should cast name[i] to unsigned char before calling isalpha(), so that you don't get any sign extension surprises:
if (isalpha((unsigned char) name[i]) == 0) { /* ... */ }
In fact, gcc nowadays will most likely give you a warning if you call any of the ctype family macros / functions with a plain char. The macros are deliberately written in such a way that a warning is shown, precisely because this is a common mistake. It is implementation-defined whether a plain char is signed or unsigned. You would get problems in a platform with signed chars because of sign extension (this is because typically, things like isalpha() are implemented using lookup tables, and extending the sign yields a negative number that would index the lookup table with a negative index - Oops!)
Other than this, this approach seems ok to me.
A third, maybe better option:
Since you mentioned fgets(), I think you could do this easily by combining fgets() with sscanf(). First, you read a line with fgets(). Then, you use sscanf() to match a string consisting of only characters in the range [a-zA-Z]. This can be done with the format specifier %[a-zA-Z]s. Then, you just have to check if this matched the entire line. Here's a working program:
#include <stdio.h>
#include <string.h>
int main(void) {
static char buf[512];
static char name[512];
int is_valid = 0;
while (!is_valid) {
fgets(buf, sizeof(buf), stdin);
size_t line_len = strlen(buf);
if (line_len > 0 && buf[line_len-1] == '\n') {
buf[line_len-1] = '\0';
line_len--;
}
int n = 0;
if (sscanf(buf, " %[a-zA-Z] %n", name, &n) == 1 && buf[n] == '\0') {
is_valid = 1;
} else {
printf("Please enter a valid name.\n");
}
}
printf("Name: %s\n", buf);
return 0;
}
Make sure your buffers are large enough; this code is vulnerable to buffer overflow for arbitrarily long names / lines.
Now let's see the code to make the first letter upper case:
//all to lower except the first letter
for(i=1; i<strlen(name); i++){
name[i] = tolower(name[i]);
}
//first letter to upper
name[0] = toupper(name[i]);
x=1;
while(name[x] != '\0'){
//if the letter before is a white space, even the first letter, it should place the first letter of a name upper
if(name[x-1] == ' ')
name[x] = toupper(name[x]);
x++;
}
Again, remove strlen() from the loop condition. toupper() and tolower() also expect an int as an argument representing either EOF or an unsigned char converted to int. You should cast it to unsigned char to avoid problems with possible sign extension, as I said earlier with the other example.
This is wrong:
//first letter to upper
name[0] = toupper(name[i]);
It should be:
//first letter to upper
name[0] = toupper(name[0]);
(The argument to toupper() is name[0], not name[i]).
Finally, this is useless:
x=1;
while(name[x] != '\0'){
//if the letter before is a white space, even the first letter, it should place the first letter of a name upper
if(name[x-1] == ' ')
name[x] = toupper(name[x]);
x++;
}
%s will never give you a string with whitespaces (refer to the manpage quote I pasted above).
Assuming that you want your name to have only characters a through z or A through Z then you could use this function
//Returns 1 if non alphabetic character is found, 0 otherwise
int NonAlphaCharsFound(char *name)
{
int FoundNonChar = 0;
int i, nameLength;
nameLength = strlen(name);
for(i = 0; i < nameLength; i++)
{
if((name[i] >= 'a' && name[i] <= 'z') || (name[i] >= 'A' && name[i] <= 'Z') || name[i] == ' ')
{
//do nothing if it's an alphabect character
//name[i] == ' ' is to allow for spaces if you want spaces in the name
}
else
{
FoundNonChar = 1;
break;
}
}
return FoundNonChar;
}
I want to calculate the length of an char array in C with a while loop.
But If I insert otto it returns the length of 5. Shouldn't be 4 the right answer?
char eingabe[255];
printf("geben Sie eine Zeile ein:");
fgets(eingabe, 255, stdin);
int i = 0;
while (eingabe[i] != '\0')
{
++i;
}
printf("Laenge: %d\n", i);
It's very likely that eingabe contains:
{ 'o', 't', 't', 'o', '\n', '\0', junk ... }
Check the man page of fgets().
Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer.
As you are reading from stdin, it stores the trailing newline [\n] character also in the supplied buffer.
Change your check to while ((eingabe[i] != '\0') && (eingabe[i] != '\n')). Hope this will solve your issue.
A newline character '\n' makes fgets stop reading, but it is considered a valid character by the function, and included in the string copied to the result. If you would like to avoid this, use fscanf like this:
fscanf(stdin, "%254[^\n]", eingabe);
Note the limit in the format: it is less than the actual length of the buffer to accommodate the null terminator.
Note: You can use strlen to compute the length of the string. It does the same thing as your for loop:
int i = strlen(eingabe);
The size of eingabe is 255. Now, if you want the number of initialized characters in it you should use strlen. But first, insert this code:
int n;
for(n = 0; n < 255; n++){
if(eingabe[n] == '\n'){
eingabe[n] = '\0';
}
}
eingabe[254] = '\0';
This code replaces the '\n' character with a NULL character. Without this, strlen will return wrong values. I also include eingabe[254] = '\0'; so that if the string read in is long enough that the newline character does not fit in the buffer, there is still a NULL character so that strlen can function properly
This is a function to read character by character from a file and place then convert the string to a float but the while loop is not terminating when a '/0' is read.
GSF555 "Gas Filter - Ford Escort" 64.50 9 <-- this is what is read in but from " 64.50 "
PKL070 "Park Lens - Toyota Corolla" 36.50 8
The while loop goes past the '/0' and also reads " 9" and characters from the next line of data.
I just have printf to see what was going wrong.
float getPrice(FILE * in){
char ch;
int i = 0;
char str[10];
ch = fgetc(in);
printf("INDEX + NUMBER = %d %c\n", i, ch);
if(ch == '\0')
ch = fgetc(in);
str[i++] = ch;
while(ch != '\0' && i < 10){
str[i++] = ch;
printf("Index I = %d\n", i);
ch = fgetc(in);
printf("3 %c\n",ch);
}
printf("STRING = %s\n", str);
return atof(str);
}
I am not sure from what I am seeing in your post where the \0 you are referring to is, but I can see a couple of problems.
First, fgetc returns an integer, not a character. This can be important for testing for the end-of-file, since the EOF is an integer with value -1, not a character which typically takes values of 0-255. You can change the declaration of ch to be an int, not a char. (Don't worry, this will not affect the print of ch with %c.)
Also, if you are trying to detect the end-of-line by testing with \0, it may not work. The end-of-line is the newline, \n. Depending on the underlying operating system, this may be take two characters, not one. You should be able to compare ch if declared as an int to the newline character, but it may not work if you keep ch as a char, if that is what you are trying to do.
the while loop is not terminating when a '/0' is read.
There's no such thing as '/0' (barring multibyte characters, for the pedants), and '\0' is a NUL whereas '0' is the zero digit. So replace those '\0' in your program with '0'. Although looking for '0' is odd; it's much more common to look for a delimiter, such as whitespace (or any other non-digit) that comes after the number.