I am a beginner coder and writing a code that
asks for the user's name
check if the length is >15, if it is, it will ask the user to input a shorter name when they restart the program
if the length is valid, upper case the first letter of the entered name
display something like "Hi name"
However, The program keeps exiting no matter what I enter. Here is what I did :
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <conio.h>
int main(void)
{
char str_name[15];
printf("Please enter your first name to begin: ");
scanf_s("%14s", str_name, _countof(str_name));
getchar();
if (strlen(str_name) > 15)
{
printf("The entered name is too long, please restart the program and try again.");
getchar();
exit(0);
}
else
{
str_name[0] = toupper(str_name[0]);
printf("Hi %s.\n", str_name);
getchar();
}
return 0;
}
You can simply use fgets() to read an input buffer.
char *fgets(char *str, int n, FILE *stream) reads a line from the specified stream and stores it in a buffer pointed to by str. It stops when either n-1 characters are read, the newline character is read, or the EOF is reached.
Some things to note about fgets():
Returns NULL on error.
Appends \n character at the end of buffer. Can replaced with \0 instead.
Buffer must be pointer to an array of characters. Either allocated on the stack or the heap.
Reads from stdin or FILE objects.
Here is some example code which shows this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define NAMESTRLEN 16
int main(void) {
char str_name[NAMESTRLEN] = {'\0'};
size_t slen;
printf("Please enter your first name to begin: ");
if (fgets(str_name, NAMESTRLEN, stdin) == NULL) {
fprintf( stderr, "Error from fgets()\n");
return 1;
}
slen = strlen(str_name);
if (slen > 0 && str_name[slen-1] == '\n') {
str_name[slen-1] = '\0';
} else {
fprintf( stderr, "Too many characters\n");
return 1;
}
if (str_name[0] == '\0') {
fprintf( stderr, "No name entered\n");
return 1;
}
str_name[0] = toupper((unsigned char)str_name[0]);
printf("Hi %s.\n", str_name);
return 0;
}
There are several issues in your code:
The buffer size is too short: scanf() will not read more than 14 bytes into str_name, so it is not possible to test if the user entered a name longer than 15 characters.
toupper() should not be given a char argument because it is only defined for values of type unsigned char and the special value EOF. Cast the char as unsigned char.
your attempt at pausing before the terminal window closes fails on windows for long names because the extra characters entered by the user are still pending after the scanf_s(). getchar() reads one and returns immediately, and the program exits and the terminal window closes. Open the terminal window and run the program manually so it does not close automatically. With this approach, you can remove the getchar() and make the program more portable.
Here is a corrected version:
#include <ctype.h>
#include <stdio.h>
int main(void) {
char str_name[17];
printf("Please enter your first name to begin: ");
if (scanf_s("%16s", str_name, sizeof(str_name))) {
printf("Premature end of file.\n");
return 1;
}
if (strlen(str_name) > 15) {
printf("The entered name is too long, please restart the program and try again.");
return 1;
}
str_name[0] = toupper((unsigned char)str_name[0]);
printf("Hi %s\n", str_name);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{
char str_name[16] = {0};
size_t len = 0;
int ch;
printf("Please enter your first name to begin: ");
while ((EOF != (ch = fgetc(stdin))) && (ch != '\n') && (len<sizeof(str_name)))
{
if (isalpha(ch))
{
str_name[len++] = ch;
}
}
if (len==sizeof(str_name))
{
fprintf(stderr, "Name too long\n");
}
else
{
str_name[len] = '\0';
printf ("Hi %c%s.\n", toupper(str_name[0]), &str_name[1]);
}
return 0;
}
As you can see I changed the input grabbing function. To check the input str len you should read byte per byte, not a whole string: fgetc do it. Using scanf with a format specifier like %14s it will return you always a trimmed string and you are not able to warn user about a too long Name.
Another point is to check that inserted chars are letters and not other kind of chars: isalpha do the job.
Moreover a c-string is composed by chars plus a null terminator ('\0', 0x00 ), so: a 15 chars string wants a 16 bytes array.
Lastly the code you wrote to mahe the first letter uppercase is completely wrong: you are passing to print a 1 char array and not a c string. My solution is one of many.
The problem is:
char Name[1]; // Declare a single element array.
Name[0] = toupper(str_name[0]); // Set it to the upper-case first letter.
// Try and print the nul-terminated string in Name - but there is no
// trailing zero (and the rest of the name is missing).
printf("Hi %s.\n", Name);
What you need is:
str_name[0] = toupper(str_name[0]);
printf("Hi %s.\n", str_name);
There is another problem that str_name[0] is a char value, and char may be signed. If you are using Windows-1252 for example, then Ä is 196, or as a signed char, -60. toupper takes an int, which must be positive¹. When -60 as a signed char is converted to int, you will get -60, and an out of range error. You need to write this as:
str_name[0] = toupper((unsigned char)str_name[0]);
printf("Hi %s.\n", str_name);
(Sorry.)
¹ Chrqlie points out the requirement is actually that the argument must be one of the values of unsigned char (which are - by definition - non-negative) or EOF (which is negative)"
Related
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char c, char_array[100];
int i = 0;
printf("Enter characters (press CTRL+D to end):\n");
while(fgets(char_array+i,sizeof(char_array)-i,stdin)) {
i = i + strlen(char_array+i);
if(char_array[i-1] == EOF)
break;
}
char_array[i-1] = '\0';
strtok(char_array,"\n");
printf("\nEnter a string:\n");
char string[100];
fgets(string,sizeof(string),stdin);
printf("\nCharacter Array: %s\n", char_array);
printf("String: %s\n", string);
return 0;
}
This is the code and I have tried many different variations(simpler) but it always has the same problem... I enter the characters, press CTRL+D and it ends without waiting for me to input a string. please help
I tried everything I could but I just cant make it work and my friends cant too... I have and exam and I need this to be done in 3 days max so I need all the help I can get.
fgets() returns NULL when the stream is closed. On Linux Ctrl-D will flush the terminal buffer if it's not empty (but fgets() will not return as it remains line buffered), and a 2nd Ctrl-D is required to trigger the EOF state of the stream.
You also want to terminate the loop if the array is full otherwise it's an infinite loop:
#define ARRAY_LEN 100
//...
while(i < ARRAY_LEN - 1 && fgets(char_array + i, ARRAY_LEN - i,stdin)) {
fgets() will not emit EOF as part of the string being read, so this is simply incorrect, and as stdin is line buffered the last character is either \n or whatever if the last character was read if the buffer is full which could be -1 or 0xff (whatever char is signed or not but that's still wrong):
if(char_array[i-1] == EOF)
break;
The next line:
char_array[i-1] = '\0';
strips the last character which is either \n or whatever we read last if the array is full (i.e. data loss).
As the input stream is in the EOF state the 2nd fgets() will return NULL. You can clear that state with clearerr(stdin) before calling fgets() to get the 2nd string. If the stream indeed ended, as in, echo "hello world" | ./your_program, the 2nd fgets() with return NULL again of course.
I suggest you use a blank line to signify end of input:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ARRAY_LEN 100
int main() {
printf("Enter characters (empty line to end):\n");
char char_array[ARRAY_LEN];
for(size_t i = 0; i < ARRAY_LEN - 1; i += strlen(char_array)) {
if(!fgets(char_array + i, ARRAY_LEN - i, stdin)) {
printf("fgets() failed\n");
return 1;
}
if(char_array[i] == '\n') {
char_array[i] = '\0';
break;
}
}
strtok(char_array, "\n");
printf("Enter a string:\n");
char string[ARRAY_LEN];
char *rv = fgets(string,sizeof(string),stdin);
printf("Character Array: %s\n", char_array);
printf("String: %s\n", string);
}
and example session:
Enter characters (empty line to end):
hello
world
Enter a string:
friend
Character Array: hello
String: friend
With stdio streams, error/eof is sticky -- that is, once an error or eof condition has occurred, further operations on the FILE * will continue to return EOF or NULL (depending on the function), rather than trying to read or write anything further.
To reset the eof state on the FILE *, you need to call clearerr(stdin). Once you do that, you can read additional input from the terminal.
As you can see, I am trying to make a program that receives getche() and then
show it and its hex and finally putting all ´getche()´es into a string but
that resulted in printing garbage chars!
Can you tell me what's the problem?
#include <conio.h>
#include <stdlib.h>
void main(void) {
char allchars[64];
int ctr = -1;
char ch = 'a';
while (ch != '\r') {
printf("\nType a character:");
ch=getche();
printf("\nhex=%x\nch=%c",ch,ch);
ctr++;
allchars[ctr] += ch;
}
char terminate = 'a';
printf("\nAll what you typed: %s",allchars);
printf("\nPress any key to continue:");
terminate=getche();
if(getche()=='\n'){
exit(0);
}
}
output:
Type a character:t
hex=74
ch=t
Type a character:e
hex=65
ch=e
Type a character:s
hex=73
ch=s
Type a character:t
hex=74
ch=t
Type a character:
hex=d
ch=
All what you typed: ä{│t
Press any key to continue:
Process returned 13 (0xD) execution time : 21.835 s
Press any key to continue.
First of all 'allchars' is not null terminated (add a '\0' at the end of the char array).
What do you think this expression does?
allchars[ctr] += ch;
Since you do not initialize 'allchars' with any value beforehand, the value at the index 'ctr' is unknown (could be anything), but you add the character 'ch' to it (add equal).
As a result, you will have garbage at that index, at least not that what you expect it to be.
At last: what if you type more than 64 characters?
There are a couple of errors in your code, and a few other issues.
First, your line allchars[ctr] += ch; is adding the value of ch to the uninitialized existing value of the element of that array; you should use the simple assignment operator, instead: allchars[ctr] = ch;.
Second, all character strings in C that are to be used by functions like printf (with the %s format specifier) must be terminated with the NUL character (a zero value); so you need to add that after your while loop.
Another probable error (depends on your compiler/platform) is that you have not included the <stdio.h> header file - so there is no formal declaration of the printf function.
And, finally (I think), you really should be declaring your main function as returning an int (not void - although that is allowed, and was more common in days past).
Here is a version of your code with the above changes made (and commented):
#include <conio.h>
#include <stdlib.h>
#include <stdio.h> // MUST include this for the "printf" function
int main(void) // Should really use "int" return type
{
char allchars[64];
int ctr = -1;
char ch = 'a';
while (ch != '\r') {
printf("\nType a character:");
ch = getche();
printf("\nhex=%x\nch=%c", ch, ch);
ctr++;
allchars[ctr] = ch; // Just assign! (Don't add to unitialized existing value.)
}
allchars[ctr + 1] = '\0'; // We MUST add a NUL-terminator to use the "%s" format
char terminate = 'a';
printf("\nAll what you typed: %s", allchars);
printf("\nPress any key to continue:");
terminate = getche();
if (getche() == '\n') {
exit(0);
}
return 0;
}
Feel free to ask for any further clarification and/or explanation.
My goal is to read every line from a piped .txt file with the getline() function, but I somehow get a error every time I use this function:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
int Chars;
int size = 10;
char *string;
printf("Please enter a string: ");
string = (char*) malloc(size);
Chars = getline(&string, &size, stdin);
if (Chars == -1)
{
puts("ERROR!");
}
else
{
puts("You entered the following string: ");
puts(string);
printf("\nCurrent size for string block: %d", Chars);
}
return 0;
}
I always get the errorcode: [Error] Id retruned 1 exit status
I've reproduced the linking error on DevC++, in which getline() seems to be missing even after forcing recent C revisions with gcc compiler options such as -std=c11.
So I've rewritten your code using fgets():
char *fgets(char *s, int size, FILE *stream);
It is for sure more portable than getline but has a few differences:
It reads up to size-1 characters if the newline is not encountered before this limit (it automatically appends the string terminator). So it doesn't manage buffer reallocation
The resulting string contains the '\n' character, if found
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_STR_SIZE 32
int main( void )
{
int len = 0;
char *str;
printf("Please enter a string: ");
str = malloc(MAX_STR_SIZE); /* (1) */
while( 1 )
{
size_t newline_pos;
fgets( str, MAX_STR_SIZE, stdin );
/* (2) */
if( len == 0) /* (3) */
{
puts("You entered the following string: ");
}
newline_pos = strcspn(str, "\n" );
str[newline_pos] = '\0';
len += strlen(str); /* (4) */
fputs(str, stdout);
if(newline_pos < MAX_STR_SIZE-1) /* (5) */
break;
}
printf("\n\nCurrent size for string block: %d", len);
free( str ); /* (6) */
return 0;
}
So, basically, I just use fgets to read from stdin, iterating until the '\n' character is found. In order to understand is this condition is met, I use strcspn() function, and I use the same function to remove the newline from the resulting string.
A few notes/assumptions (check the corresponding number in code section):
Casting the result of malloc is required only if you are compiling with a C++ compiler. It can be omitted in C
Removed fgets error check: it returns NULL in case of error (no chars read before EOF is found. It won't happen reading from stdin)
Checking for len==0 we make sure that the "You entered the following string: " is printed only once
The length of the string is calculated by summing the length of the strings read in every iteration
The break condition is met when the string contains '\n'. Otherwise strcspn's return value will be MAX_STR_SIZE
Even if the OS will release all the dynamic memory used by the program, on return, it is a good habit always freeing it anyway
i am trying to create a looping which keeps looping till "only" newline charater is inputted or maybe just a space (until nothing is entered to the input line).
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num;
while(1)
{
scanf("%d",&num);
if(num==NULL)
break;
printf("%d",num);
}
return 0;
}
You can't do that with scanf (at least not easily). If you want to process user input, scanf is a bad choice (in fact, in all my years of developing in C, I've never used scanf; I recommend you avoid it altogether).
num==NULL makes no sense: num is a number, but NULL is a pointer value. If you want to check whether scanf was successful, you need to check its return value.
I'd do something like:
char line[100];
while (fgets(line, sizeof line, stdin)) { // read input line by line
int num;
if (sscanf(line, "%d", &num) != 1) { // the line didn't start with a valid integer
break;
}
printf("%d\n", num);
}
If you want to check specifically for an empty string, not just something that doesn't look like a number, you could use strspn:
if (line[strspn(line, " \t\n")] == '\0') {
// line contains spaces / tabs / newlines only
There are other things that can be on a line other than an integer. Your code indicates an integer expected, but your text only indicates the line is blank or only contains a space.
Given your text in the question:
#include <stdio.h>
#include <string.h>
int main( void )
{
char line[1024];
while( fgets( line, sizeof( line ), stdin ) )
{
if( (strlen( line ) == 1 )
|| (strlen( line ) == 2 && line[0] == ' '))
{
// all done
break;
}
else
{
// process line
}
} // end while
}
I'm trying to make a function to validate mobile entry, the mobile number MUST starts with 0 and is 11 numbers (01281220427 for example.)
I want to make sure that the program gets the right entry.
This is my attempt:
#include <stdio.h>
#include <strings.h>
void integerValidation(char x[15]);
int main(int argc, char **argv)
{
char mobile[15];
integerValidation(mobile);
printf("%s\n\n\n", mobile);
return 0;
}
void integerValidation(char x[15]){
char input[15];
long int num = -1;
char *cp, ch;
int n;
printf("Please enter a valid mobile number:");
while(num<0){
cp = fgets(input, sizeof(input), stdin);
if (cp == input) {
n = sscanf(input, "%ld %c", &num, &ch);
if (n!=1) {printf("ERROR! Please enter a valid mobile number:");
num = -1;
}
else if (num<0)
printf("ERROR! Please enter a valid mobile number:");
else if ((strlen(input)-1)>11 || (strlen(input)-1)<11 || strncmp(&input[0], "0", 1) != 0){
printf("ERROR! Please enter a valid mobile number:");
num = -1;
}
}
}
long int i;
i = strlen(input);
//Because when I try to print it out it prints a line after number.
strcpy(&input[i-1], "");
strcpy(x, input);
}
Now, if I don't use
strcpy(&input[i-1], "");
the array prints a new line after the number, what would be a good fix other than mine? and how can I make this function optimized and shorter?
Thanks in advance!
Edit:
My question is: 1. Why does the input array prints a new line in the end?
2. How can I make this code shorter?
End of edit.
If you insist on using sscanf(), you should change the format this way:
int integerValidation(char x[15]) {
char input[15], c;
printf("Please enter a valid mobile number:");
while (fgets(input, sizeof(input), stdin)) {
if (sscanf(input, "%11[0123456789]%c", x, &c) == 2
&& x[0] == '0' && strlen(x) == 11 && c == '\n') {
// number stored in `x` is correct
return 1;
}
printf("ERROR! Please enter a valid mobile number:");
}
x[0] = '\0'; // no number was input, end of file reached
return 0;
}
%12[0123456789] parses at most 11 characters that must be digits.
%c reads the following character, which should be the trailing '\n'.
I verify that both formats have been matched, and the number starts with 0 (x[0] == '0') and it has exactly 11 digits.
You're seeing the newline, since fgets() reads until an EOF or a newline is received. The newline is stored in the buffer, and after that the string is terminated with '\0'.
An alternative would be to directly overwrite the newline with another null-byte: input[i-1] = '\0' (which basically does the same thing as your solution, but saves a function call).
The same goes for the check with strncmp with length 1, you can directly check input[0] == '0'. Note that you have to compare against '0' (char) here, not "0" (string).
A few other things I'm seeing:
You can also spare the %c in the format string for sscanf (you're never evaluating it anyway, since you're checking for 1 as return value), which also eliminates the need for char ch.
Also, you're passing char x[15] as argument to your function. This is a bit misleading, because what actually gets passed is a pointer to a char array (try using sizeof(x), your compiler will most likely issue a warning about the size of char * being returned by sizeof()).
What you could do is to ditch the char array input, which you're using as temporary buffer, and use the buffer which was handed over as argument. For this to be save, you should use a second funcion parameter to specify the size of the buffer which was handed to the function, which would result in a function header like as follows:
void integerValidation(char *input, size_t len);
With this, you'd have to use len instead of sizeof(input). The following question provides more detail why: C: differences between char pointer and array
Since you're not using a temporary buffer anymore, you can remove the final call to strcpy().
There are also a lot of checks for the number length/format. You can save a few:
If you use %lu instead of %ld no signed numbers are being converted, which saves you the check for num < 0.
You're checking whether the length of the read number is <11 or >11 - why not just check for !=11?
You're calling strlen() three times on the input-buffer (or still twice with the reworked check for lengh 11) - it makes sense to call it once, save the length in a variable and use that variable from then on, since you're not altering the string between the calls.
There is already an accepted answer, but for what it's worth, here is another.
I made several changes to your code, firstly avoiding "magic numbers" by defining the phone number length and an arbitrarily greater string length. Then there is no point passing an array x[15] to a function since it pays no regard to its length, might as well use the simpler *x pointer. Next, I return all reasons for failure back to the caller, that's simpler. And instead of trying to treat the phone number as a numeric entry (note: letters, spaces, hyphens, commas and # can sometimes be a part of phone number too) I stick to a character string. Another reason is that the required leading zero will vanish if you convert the entry to an int of some size. I remove the trailing newline that fgets() reads with the input line, and the result is this.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAXLEN 11
#define STRLEN (MAXLEN+10)
int integerValidation(char *x);
int main(int argc, char **argv)
{
char mobile[STRLEN];
while (!integerValidation(mobile)) // keep trying
printf("Invalid phone number\n");
printf("%s\n\n\n", mobile); // result
return 0;
}
int integerValidation(char *x)
{
int i, len;
printf("Please enter a valid mobile number:");
if(fgets(x, STRLEN, stdin) == NULL) // check bad entry
return 0;
x [ strcspn(x, "\r\n") ] = 0; // remove trailing newline etc
if((len = strlen(x)) != MAXLEN) // check length
return 0;
if(x[0] != '0') // check leading 0
return 0;
for(i=1; i<len; i++) // check all other chars are numbers
if(!isdigit(x[i]))
return 0;
return 1; // success
}