How to correctly input a string in C - c

I am currently learning C, and so I wanted to make a program that asks the user to input a string and to output the number of characters that were entered, the code compiles fine, when I enter just 1 character it does fine, but when I enter 2 or more characters, no matter what number of character I enter, it will always say there is just one character and crashes after that. This is my code and I can't figure out what is wrong.
int main(void)
{
int siz;
char i[] = "";
printf("Enter a string.\n");
scanf("%s", i);
siz = sizeof(i)/sizeof(char);
printf("%d", siz);
getch();
return 0;
}
I am currently learning to program, so if there is a way to do it using the same scanf() function I will appreciate that since I haven't learned how to use any other function and probably won't understand how it works.

Please, FORGET that scanf exists. The problem you are running into, whilst caused mostly by your understandable inexperience, will continue to BITE you even when you have experience - until you stop.
Here is why:
scanf will read the input, and put the result in the char buffer you provided. However, it will make no check to make sure there is enough space. If it needs more space than you provided, it will overwrite other memory locations - often with disastrous consequences.
A safer method uses fgets - this is a function that does broadly the same thing as scanf, but it will only read in as many characters as you created space for (or: as you say you created space for).
Other observation: sizeof can only evaluate the size known at compile time : the number of bytes taken by a primitive type (int, double, etc) or size of a fixed array (like int i[100];). It cannot be used to determine the size during the program (if the "size" is a thing that changes).
Your program would look like this:
#include <stdio.h>
#include <string.h>
#define BUFLEN 100 // your buffer length
int main(void) // <<< for correctness, include 'void'
{
int siz;
char i[BUFLEN]; // <<< now you have space for a 99 character string plus the '\0'
printf("Enter a string.\n");
fgets(i, BUFLEN, stdin); // read the input, copy the first BUFLEN characters to i
siz = sizeof(i)/sizeof(char); // it turns out that this will give you the answer BUFLEN
// probably not what you wanted. 'sizeof' gives size of array in
// this case, not size of string
// also not
siz = strlen(i) - 1; // strlen is a function that is declared in string.h
// it produces the string length
// subtract 1 if you don't want to count \n
printf("The string length is %d\n", siz); // don't just print the number, say what it is
// and end with a newline: \n
printf("hit <return> to exit program\n"); // tell user what to do next!
getc(stdin);
return 0;
}
I hope this helps.
update you asked the reasonable follow-up question: "how do I know the string was too long".
See this code snippet for inspiration:
#include <stdio.h>
#include <string.h>
#define N 50
int main(void) {
char a[N];
char *b;
printf("enter a string:\n");
b = fgets(a, N, stdin);
if(b == NULL) {
printf("an error occurred reading input!\n"); // can't think how this would happen...
return 0;
}
if (strlen(a) == N-1 && a[N-2] != '\n') { // used all space, didn't get to end of line
printf("string is too long!\n");
}
else {
printf("The string is %s which is %d characters long\n", a, strlen(a)-1); // all went according to plan
}
}
Remember that when you have space for N characters, the last character (at location N-1) must be a '\0' and since fgets includes the '\n' the largest string you can input is really N-2 characters long.

This line:
char i[] = "";
is equivalent to:
char i[1] = {'\0'};
The array i has only one element, the program crashes because of buffer overflow.
I suggest you using fgets() to replace scanf() like this:
#include <stdio.h>
#define MAX_LEN 1024
int main(void)
{
char line[MAX_LEN];
if (fgets(line, sizeof(line), stdin) != NULL)
printf("%zu\n", strlen(line) - 1);
return 0;
}
The length is decremented by 1 because fgets() would store the new line character at the end.

The problem is here:
char i[] = "";
You are essentially creating a char array with a size of 1 due to setting it equal to "";
Instead, use a buffer with a larger size:
char i[128]; /* You can also malloc space if you desire. */
scanf("%s", i);
See the link below to a similar question if you want to include spaces in your input string. There is also some good input there regarding scanf alternatives.
How do you allow spaces to be entered using scanf?

That's because char i[] = ""; is actually an one element array.
Strings in C are stored as the text which ends with \0 (char of value 0). You should use bigger buffer as others said, for example:
char i[100];
scanf("%s", i);
Then, when calculating length of this string you need to search for the \0 char.
int length = 0;
while (i[length] != '\0')
{
length++;
}
After running this code length contains length of the specified input.

You need to allocate space where it will put the input data. In your program, you can allocate space like:
char i[] = " ";
Which will be ok. But, using malloc is better. Check out the man pages.

Related

How do you prevent buffer overflow using fgets?

So far I have been using if statements to check the size of the user-inputted strings. However, they don't see to be very useful: no matter the size of the input, the while loop ends and it returns the input to the main function, which then just outputs it.
I don't want the user to enter anything greater than 10, but when they do, the additional characters just overflow and are outputted on a newline. The whole point of these if statements is to stop that from happening, but I haven't been having much luck.
#include <stdio.h>
#include <string.h>
#define SIZE 10
char *readLine(char *buf, size_t sz) {
int true = 1;
while(true == 1) {
printf("> ");
fgets(buf, sz, stdin);
buf[strcspn(buf, "\n")] = 0;
if(strlen(buf) < 2 || strlen(buf) > sz) {
printf("Invalid string size\n");
continue;
}
if(strlen(buf) > 2 && strlen(buf) < sz) {
true = 0;
}
}
return buf;
}
int main(int argc, char **argv) {
char buffer[SIZE];
while(1) {
char *input = readLine(buffer, SIZE);
printf("%s\n", input);
}
}
Any help towards preventing buffer overflow would be much appreciated.
When the user enters in a string longer than sz, your program processes the first sz characters, but then when it gets back to the fgets call again, stdin already has input (the rest of the characters from the user's first input). Your program then grabs another up to sz characters to process and so on.
The call to strcspn is also deceiving because if the "\n" is not in the sz chars you grab than it'll just return sz-1, even though there's no newline.
After you've taken input from stdin, you can do a check to see if the last character is a '\n' character. If it's not, it means that the input goes past your allowed size and the rest of stdin needs to be flushed. One way to do that is below. To be clear, you'd do this only when there's been more characters than allowed entered in, or it could cause an infinite loop.
while((c = getchar()) != '\n' && c != EOF)
{}
However, trying not to restructure your code too much how it is, we'll need to know if your buffer contains the newline before you set it to 0. It will be at the end if it exists, so you can use the following to check.
int containsNewline = buf[strlen(buf)-1] == '\n'
Also be careful with your size checks, you currently don't handle the case for a strlen of 2 or sz. I would also never use identifier names like "true", which would be a possible value for a bool variable. It makes things very confusing.
In case that string inside the file is longer that 10 chars, your fgets() reads only the first 10 chars into buf. And, because these chars doesn't contain the trailing \n, function strcspn(buf, "\n") returns 10 - it means, you are trying to set to 0 an buf[10], so it is over buf[] boundaries (max index is 9).
Additionally, never use true or false as the name of variable - it totally diminishes the code. Use something like 'ok' instead.
Finally: please clarify, what output is expected in case the file contains string longer than 10 characters. It should be truncated?

C - Print ASCII Value for Each Character in a String

I'm new to C and I'm trying to write a program that prints the ASCII value for every letter in a name that the user enters. I attempted to store the letters in an array and try to print each ASCII value and letter of the name separately but, for some reason, it only prints the value of the first letter.
For example, if I write "Anna" it just prints 65 and not the values for the other letters in the name. I think it has something to do with my sizeof(name)/sizeof(char) part of the for loop, because when I print it separately, it only prints out 1.
I can't figure out how to fix it:
#include <stdio.h>
int main(){
int e;
char name[] = "";
printf("Enter a name : \n");
scanf("%c",&name);
for(int i = 0; i < (sizeof(name)/sizeof(char)); i++){
e = name[i];
printf("The ASCII value of the letter %c is : %d \n",name[i],e);
}
int n = (sizeof(name)/sizeof(char));
printf("%d", n);
}
Here's a corrected, annotated version:
#include <stdio.h>
#include <string.h>
int main() {
int e;
char name[100] = ""; // Allow for up to 100 characters
printf("Enter a name : \n");
// scanf("%c", &name); // %c reads a single character
scanf("%99s", name); // Use %s to read a string! %99s to limit input size!
// for (int i = 0; i < (sizeof(name) / sizeof(char)); i++) { // sizeof(name) / sizeof(char) is a fixed value!
size_t len = strlen(name); // Use this library function to get string length
for (size_t i = 0; i < len; i++) { // Saves calculating each time!
e = name[i];
printf("The ASCII value of the letter %c is : %d \n", name[i], e);
}
printf("\n Name length = %zu\n", strlen(name)); // Given length!
int n = (sizeof(name) / sizeof(char)); // As noted above, this will be ...
printf("%d", n); // ... a fixed value (100, as it stands).
return 0; // ALWAYS return an integer from main!
}
But also read the comments given in your question!
This is a rather long answer, feel free to skip to the end for the code example.
First of all, by initialising a char array with unspecified length, you are making that array have length 1 (it only contains the empty string). The key issue here is that arrays in C are fixed size, so name will not grow larger.
Second, the format specifier %c causes scanf to only ever read one byte. This means that even if you had made a larger array, you would only be reading one byte to it anyway.
The parameter you're giving to scanf is erroneous, but accidentally works - you're passing a pointer to an array when it expects a pointer to char. It works because the pointer to the array points at the first element of the array. Luckily this is an easy fix, an array of a type can be passed to a function expecting a pointer to that type - it is said to "decay" to a pointer. So you could just pass name instead.
As a result of these two actions, you now have a situation where name is of length 1, and you have read exactly one byte into it. The next issue is sizeof(name)/sizeof(char) - this will always equal 1 in your program. sizeof char is defined to always equal 1, so using it as a divisor causes no effect, and we already know sizeof name is equal to 1. This means your for loop will only ever read one byte from the array. For the exact same reason n is equal to 1. This is not erroneous per se, it's just probably not what you expected.
The solution to this can be done in a couple of ways, but I'll show one. First of all, you don't want to initialize name as you do, because it always creates an array of size 1. Instead you want to manually specify a larger size for the array, for instance 100 bytes (of which the last one will be dedicated to the terminating null byte).
char name[100];
/* You might want to zero out the array too by eg. using memset. It's not
necessary in this case, but arrays are allowed to contain anything unless
and until you replace their contents.
Parameters are target, byte to fill it with, and amount of bytes to fill */
memset(name, 0, sizeof(name));
Second, you don't necessarily want to use scanf at all if you're reading just a byte string from standard input instead of a more complex formatted string. You could eg. use fgets to read an entire line from standard input, though that also includes the newline character, which we'll have to strip.
/* The parameters are target to write to, bytes to write, and file to read from.
fgets writes a null terminator automatically after the string, so we will
read at most sizeof(name) - 1 bytes.
*/
fgets(name, sizeof(name), stdin);
Now you've read the name to memory. But the size of name the array hasn't changed, so if you used the rest of the code as is you would get a lot of messages saying The ASCII value of the letter is : 0. To get the meaningful length of the string, we'll use strlen.
NOTE: strlen is generally unsafe to use on arbitrary strings that might not be properly null-terminated as it will keep reading until it finds a zero byte, but we only get a portable bounds-checked version strnlen_s in C11. In this case we also know that the string is null-terminated, because fgets deals with that.
/* size_t is a large, unsigned integer type big enough to contain the
theoretical maximum size of an object, so size functions often return
size_t.
strlen counts the amount of bytes before the first null (0) byte */
size_t n = strlen(name);
Now that we have the length of the string, we can check if the last byte is the newline character, and remove it if so.
/* Assuming every line ends with a newline, we can simply zero out the last
byte if it's '\n' */
if (name[n - 1] == '\n') {
name[n - 1] = '\0';
/* The string is now 1 byte shorter, because we removed the newline.
We don't need to calculate strlen again, we can just do it manually. */
--n;
}
The loop looks quite similar, as it was mostly fine to begin with. Mostly, we want to avoid issues that can arise from comparing a signed int and an unsigned size_t, so we'll also make i be type size_t.
for (size_t i = 0; i < n; i++) {
int e = name[i];
printf("The ASCII value of the letter %c is : %d \n", name[i], e);
}
Putting it all together, we get
#include <stdio.h>
#include <string.h>
int main() {
char name[100];
memset(name, 0, sizeof(name));
printf("Enter a name : \n");
fgets(name, sizeof(name), stdin);
size_t n = strlen(name);
if (n > 0 && name[n - 1] == '\n') {
name[n - 1] = '\0';
--n;
}
for (size_t i = 0; i < n; i++){
int e = name[i];
printf("The ASCII value of the letter %c is : %d \n", name[i], e);
}
/* To correctly print a size_t, use %zu */
printf("%zu\n", n);
/* In C99 main implicitly returns 0 if you don't add a return value
yourself, but it's a good habit to remember to return from functions. */
return 0;
}
Which should work pretty much as expected.
Additional notes:
This code should be valid C99, but I believe it's not valid C89. If you need to write to the older standard, there are several things you need to do differently. Fortunately, your compiler should warn you about those issues if you tell it which standard you want to use. C99 is probably the default these days, but older code still exists.
It's a bit inflexible to be reading strings into fixed-size buffers like this, so in a real situation you might want to have a way of dynamically increasing the size of the buffer as necessary. This will probably require you to use C's manual memory management functionality like malloc and realloc, which aren't particularly difficult but take greater care to avoid issues like memory leaks.
It's not guaranteed the strings you're reading are in any specific encoding, and C strings aren't really ideal for handling text that isn't encoded in a single-byte encoding. There is support for "wide character strings" but probably more often you'll be handling char strings containing UTF-8 where a single codepoint might be multiple bytes, and might not even represent an individual letter as such. In a more general-purpose program, you should keep this in mind.
If we need write a code to get ASCII values of all elements in a string, then we need to use "%d" instead of "%c". By doing this %d takes the corresponding ascii value of the following character.
If we need to only print the ascii value of each character in the string. Then this code will work:
#include <stdio.h>
char str[100];
int x;
int main(){
scanf("%s",str);
for(x=0;str[x]!='\0';x++){
printf("%d\n",str[x]);
}
}
To store all corresponding ASCII value of character in a new variable, we need to declare an integer variable and assign it to character. By this way the integer variable stores ascii value of character. The code is:
#include <stdio.h>
char str[100];
int x,ascii;
int main(){
scanf("%s",str);
for(x=0;str[x]!='\0';x++){
ascii=str[x];
printf("%d\n",ascii);
}
}
I hope this answer helped you.....😊

C - Using fgets until newline/-1 [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
So I'm trying to make it so that you can write text into a file until you make a newline or type -1. My problem is that when you write, it just keeps going until it crashes and gives the error "Stack around the variable "inputChoice" was corrupted".
I believe the problem is that the program doesn't stop accepting stdin when you want to stop typing (-1, newline) and that causes the error. I've tried with a simple scanf and it works, but you can only write a word. No spaces and it doesn't support multiple lines either. That's why I have to use fgets
Judging from your comments, I assume that there are some basic concepts in C
that you haven't fully understood, yet.
C-Strings
A C-String is a sequence of bytes. This sequence must end with the value 0.
Every value in the sequence represents a character based on the
ASCII encoding, for example the
character 'a' is 97, 'b' is 98, etc. The character '\0' has
the value 0 and it's the character that determines the end of the string.
That's why you hear a lot that C-Strings are '\0'-terminated.
In C you use an array of chars (char string[], char string[SOME VALUE]) to
save a string. For a string of length n, you need an array of dimension n+1, because
you also need one space for the terminating '\0' character.
When dealing with strings, you always have to think about the proper type,
whether your are using an array or a pointer. A pointer
to char doesn't necessarily mean that you are dealing with a C-String!
Why am I telling you this? Because of:
char inputChoice = 0;
printf("Do you wish to save the Input? (Y/N)\n");
scanf("%s", &inputChoice);
I haven't changed much, got very demotivated after trying for a while.
I changed the %s to an %c at scanf(" %c, &inputChoice) and that
seems to have stopped the program from crashing.
which shows that haven't understood the difference between %s and %c.
The %c conversion specifier character tells scanf that it must match a single character and it expects a pointer to char.
man scanf
c
Matches a sequence of characters whose length is specified by the maximum field
width (default 1); the next pointer must be a
pointer to char, and there must be enough room for all the characters
(no terminating null byte is added). The usual skip of
leading white space is suppressed. To skip white space first, use an explicit space in the format.
Forget the bit about the length, it's not important right now.
The important part is in bold. For the format scanf("%c", the function
expects a pointer to char and its not going to write the terminating '\0'
character, it won't be a C-String. If you want to read one letter and one
letter only:
char c;
scanf("%c", &c);
// also possible, but only the first char
// will have a defined value
char c[10];
scanf("%c", c);
The first one is easy to understand. The second one is more interesting: Here
you have an array of char of dimension 10 (i.e it holds 10 chars). scanf
will match a single letter and write it on c[0]. However the result won't be
a C-String, you cannot pass it to puts nor to other functions that expect
C-Strings (like strcpy).
The %s conversion specifier character tells scanf that it must match a sequence of non-white-space characters
man scanf
s
Matches a sequence of non-white-space characters; the next pointer must be a
pointer to the initial element of a character array that is long enough to
hold the input sequence and the terminating null byte ('\0'), which is added
automatically.
Here the result will be that a C-String is saved. You also have to have enough
space to save the string:
char string[10];
scanf("%s", string);
If the strings matches 9 or less characters, everything will be fine, because
for a string of length 9 requires 10 spaces (never forget the terminating
'\0'). If the string matches more than 9 characters, you won't have enough
space in the buffer and a buffer overflow (accessing beyond the size) occurs.
This is an undefined behaviour and anything can happen: your program might
crash, your program might not crash but overwrites another variable and thus
scrwes the flow of your program, it could even kill a kitten somewhere, do
you really want to kill kittens?
So, do you see why your code is wrong?
char inputChoice = 0;
scanf("%s", &inputChoice);
inputChoice is a char variable, it can only hold 1 value.
&inputChoice gives you the address of the inputChoice variable, but the
char after that is out of bound, if you read/write it, you will have an
overflow, thus you kill a kitten. Even if you enter only 1 character, it will
write at least 2 bytes and because you it only has space for one character, a kitten will die.
So, let's talk about your code.
From the perspective of an user: Why would I want to enter lines of text, possibly a lot of lines of text
and then answer "No, I don't want to save the lines". It doesn't make sense to
me.
In my opinion you should first ask the user whether he/she wants to save the
input first, and then ask for the input. If the user doesn't want to save
anything, then there is no point in asking the user to enter anything at
all. But that's just my opinion.
If you really want to stick to your plan, then you have to save every line and
when the user ends entering data, you ask and you save the file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFERLEN 1024
void printFile () {
int i;
char openFile[BUFFERLEN];
FILE *file;
printf("What file do you wish to write in?\n");
scanf("%s", openFile);
getchar();
file = fopen(openFile, "w");
if (file == NULL) {
printf("Could not open file.\n");
return;
}
// we save here all lines to be saved
char **lines = NULL;
int num_of_lines = 0;
char buffer[BUFFERLEN];
printf("Enter an empty line of -1 to end input\n");
// for simplicity, we assume that no line will be
// larger than BUFFERLEN - 1 chars
while(fgets(buffer, sizeof buffer, stdin))
{
// we should check if the last character is \n,
// if not, buffer was not large enough for the line
// or the stream closed. For simplicity, I will ignore
// these cases
int len = strlen(buffer);
if(buffer[len - 1] == '\n')
buffer[len - 1] = '\0';
if(strcmp(buffer, "") == 0 || strcmp(buffer, "-1") == 0)
break; // either an empty line or user entered "-1"
char *line = strdup(buffer);
if(line == NULL)
break; // if no more memory
// process all lines that already have been entered
char **tmp = realloc(lines, (num_of_lines+1) * sizeof *tmp);
if(tmp == NULL)
{
free(line);
break; // same reason as for strdup failing
}
lines = tmp;
lines[num_of_lines++] = line; // save the line and increase num_of_lines
}
char inputChoice = 0;
printf("Do you wish to save the Input? (Y/N)\n");
scanf("%c", &inputChoice);
getchar();
if (inputChoice == 'Y' || inputChoice == 'y') {
for(i = 0; i < num_of_lines; ++i)
fprintf(file, "%s\n", lines[i]); // writing every line
printf("Your file has been saved\n");
printf("Please press any key to continue");
getchar();
}
// closing FILE buffer
fclose(file);
// free memory
if(num_of_lines)
{
for(i = 0; i < num_of_lines; ++i)
free(lines[i]);
free(lines);
}
}
int main(void)
{
printFile();
return 0;
}
Remarks on the code
I used the same code as yours as the base for mine, so that you can spot the
differences much quicker.
I use the macro BUFFERLEN for declaring the length of the buffers. That's
my style.
Look at the fgets line:
fgets(buffer, sizeof buffer, stdin)
I use here sizeof buffer instead of 1024 or BUFFERLEN. Again, that's my
style, but I think doing this is better, because even if you change the size
of the buffer by changing the macro, or by using another explicit size, sizeof buffer
will always return the correct size. Be aware that this only works when
buffer is an array.
The function strdup returns a pointer a pointer to a new string that
duplicates the argument. It's used to create a new copy of a string. When
using this function, don't forget that you have to free the memory using
free(). strdup is not part of the standard library, it conforms
to SVr4, 4.3BSD, POSIX.1-2001. If you use Windows (I don't use Windows,
I'm not familiar with the Windows ecosystem), this function might not be
present. In that case you can write your own:
char *strdup(const char *s)
{
char *str = malloc(strlen(s) + 1);
if(str == NULL)
return NULL;
strcpy(str, s);
return str;
}

Problems with STRCPY and STRCMP when finding the smallest and largest problems

I'm writing a program to find the smallest and largest word according to the dictionary order in K.N.King's problem. Find the largest and smallest of a word until the user inputs a 4 letter word.
Firstly, I use strcmp to compare the input word with the largest or smallest. then using strcpy to copy the input string to the largest or smallest.
#include <string.h>
#include <stdio.h>
main()
{
char inputStr[20] ;
char max[20];
char min[20];
int length =0;
do
{
printf("pls, input your string: ");
gets(inputStr);
if(strcmp(inputStr,max) > 0)
strcpy(max,inputStr);
if (strcmp(inputStr,min) < 0)
strcpy(min,inputStr);
length = strlen(inputStr);
}
while (length != 4);
printf("largest word is: %s\n",max);
printf("smallest word is: %s",min);
}
for example.
Enter Word : Cat
Enter Word : Dog
Enter Word : penguin
Enter Word : bear
the smallest word is bear
the largest word is penguin
However, when running programs, the largest word is always a special character, and the smallest is always right. My program shows the result that
the largest word is:
the smallest word is: bear
You don't asctually initialise max or min so they will be set to arbitrary values when you first compare them.
You can fix this by simply doing setting them to the first word regardless of the comparison:
int firstTime = 1;
do
{
printf("Please input your string: ");
gets(inputStr);
if (firstTime || (strcmp(inputStr, max) > 0))
strcpy(max, inputStr);
if (firstTime || (strcmp(inputStr, min) < 0))
strcpy(min, inputStr);
firstTime = 0;
length = strlen(inputStr);
}
And, as an aside, there's a reason why gets was deprecated and later removed from the standard, there is no way to protect against buffer overflow if you use this function. Further details can be found here, which also includes a very handy solution to the problem.
I suspect the main issue is that either max or min will always be the incorrect, as they are empty (or filled with garbage) to begin with. You should reformat your code to be in the style:
min = max = initial-input()
length = len(min)
while (length != 4)
do stuff
I also recommend using fgets() or getline() for reading input, just in case you decide to put in 100 characters when you only set aside space for 20. Same with strcpy(), it should be replaced by strncpy() just in case. So the result will look something like:
...
fgets(inputStr, 20, stdin);
strncpy(max, inputStr, 20);
strncpy(min, inputStr, 20);
length = strlen(inputStr);
while(length != 4) {
...
}
The problem is due to uninitialized char array. This(using it in strcmp) is undefined behavior. Also logically your code won't work properly. strcasecmp is not part of standard - it is a POSIX thing.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAXLETTER 20
int main(void)
{
char inputStr[MAXLETTER] ;
char max[MAXLETTER];
char min[MAXLETTER];
size_t length =0;
bool flag = true;
do
{
printf("pls, input your string: ");
if( fgets(inputStr,sizeof inputStr,stdin) == NULL){
fprintf(stderr, "%s\n", "Error in input");
exit(1);
}
inputStr[strcspn(inputStr,"\n")]='\0';
if(flag){
strncpy(max,inputStr,MAXLETTER-1);
strncpy(min,inputStr,MAXLETTER-1);
max[MAXLETTER-1]=0;
min[MAXLETTER-1]=0;
flag = false;
}
if(strcasecmp(inputStr,max) > 0){
strncpy(max,inputStr,MAXLETTER-1);
max[MAXLETTER-1]=0;
}
if (strcasecmp(inputStr,min) < 0){
strncpy(min,inputStr,MAXLETTER-1);
min[MAXLETTER-1]=0;
}
length = strlen(inputStr);
}
while (length != 4);
printf("largest word is: %s\n",max);
printf("smallest word is: %s",min);
return 0;
}
Compile your program using gcc -Wall -Wextra -Werror progname.c, it will tell you where you are going wrong.
One thing, Don't use gets().
I'm wrong because I don't initialize max and min. However, the program still runs with min...
The thing it is called Undefined behavior. It may work some time and
may not. That's the thing about it. Without initializzing when you
compare then behavior is not defined. It may get some error , may
suprisingly give correct result.
Revised
#include <stdio.h>
#include <string.h>
#define N 20
int main( void )
{
char max[N];
char min[N];
char (*ch)[N];
char inputStr[N] ;
int length = 0;
fgets(inputStr, sizeof(inputStr), stdin);
// Technique from https://stackoverflow.com/a/28462221/701302
inputStr[strcspn(inputStr, "\n")] = 0;
// Set both max and min to initial input in order to ...
strcpy(max,inputStr);
strcpy(min,inputStr);
do
{
fgets(inputStr, sizeof(inputStr), stdin);
inputStr[strcspn(inputStr, "\n")] = 0;
// ... now have basis for valid comparison
if (strcmp(inputStr,max) > 0){
strcpy(max,inputStr);
}
else
if ( strcmp(inputStr,min) < 0){
strcpy(min,inputStr);
}
length = strlen(inputStr);
} while (length != 4);
printf("largest word is: %s\n",max);
ch = &min;
if (strcmp(ch,"") == 0){
ch = "[empty string]";
}
printf("smallest word is: %s",ch);
}
See live code.
Note: it is much safer to use fgets() than gets(). The reason gets() is dangerous is b/c of potential buffer overflows per this article. However, with fgets() the input may terminate with a newline so you need to get rid of it. Although you may use strtok() for that even tho' it wasn't designed with that possibility in mind, as chux remarks it is inadequate if the user's input consists of a newline character.
I revised this answer again, taking a cue from here. The technique utilizes strcspn() which returns the number of characters in str1 not in str2, So, the newline gets replaced every time whether the input consists of one or more printable characters or a newline. I accordingly revised both the code and input at ideaone.com. So, now the output reflects the largest word is penguin and the smallest word is the empty string. But, if you run the code using only the original input of the OP, then the result will be penguin and bear as respectively the largest and smallest words lexicographically speaking.

Why fgets is not inputting first value?

I am writing a program to write my html files rapidly. And when I came to write the content of my page I got a problem.
#include<stdio.h>
int main()
{
int track;
int question_no;
printf("\nHow many questions?\t");
scanf("%d",&question_no);
char question[question_no][100];
for(track=1;track<=question_no;track++)
{
printf("\n<div class=\"question\">%d. ",track);
printf("\nQuestion number %d.\t",track);
fgets(question[track-1],sizeof(question[track-1]),stdin);
printf("\n\n\tQ%d. %s </div>",track,question[track-1]);
}
}
In this program I am writing some questions and their answers (in html file). When I test run this program I input the value of question_no to 3. But when I enter my first question it doesn't go in question[0] and consequently the first question doesn't output. The rest of the questions input without issue.
I searched some questions on stackoverflow and found that fgets() looks for last \0 character and that \0 stops it.
I also found that I should use buffer to input well through fgets() so I used: setvbuf and setbuf but that also didn't work (I may have coded that wrong). I also used fflush(stdin) after my first and last (as well) scanf statement to remove any \0 character from stdin but that also didn't work.
Is there any way to accept the first input by fgets()?
I am using stdin and stdout for now. I am not accessing, reading or writing any file.
Use fgets for the first prompt too. You should also malloc your array as you don't know how long it is going to be at compile time.
#include <stdlib.h>
#include <stdio.h>
#define BUFSIZE 8
int main()
{
int track, i;
int question_no;
char buffer[BUFSIZE], **question;
printf("\nHow many questions?\t");
fgets(buffer, BUFSIZE, stdin);
question_no = strtol(buffer, NULL, 10);
question = malloc(question_no * sizeof (char*));
if (question == NULL) {
return EXIT_FAILURE;
}
for (i = 0; i < question_no; ++i) {
question[i] = malloc(100 * sizeof (char));
if (question[i] == NULL) {
return EXIT_FAILURE;
}
}
for(track=1;track<=question_no;track++)
{
printf("\n<div class=\"question\">%d. ",track);
printf("\nQuestion number %d.\t",track);
fgets(question[track-1],100,stdin);
printf("\n\n\tQ%d. %s </div>",track,question[track-1]);
}
for (i = 0; i < question_no; ++i) free(question[i]);
free(question);
return EXIT_SUCCESS;
}
2D arrays in C
A 2D array of type can be represented by an array of pointers to type, or equivalently type** (pointer to pointer to type). This requires two steps.
Using char **question as an exemplar:
The first step is to allocate an array of char*. malloc returns a pointer to the start of the memory it has allocated, or NULL if it has failed. So check whether question is NULL.
Second is to make each of these char* point to their own array of char. So the for loop allocates an array the size of 100 chars to each element of question. Again, each of these mallocs could return NULL so you should check for that.
Every malloc deserves a free so you should perform the process in reverse when you have finished using the memory you have allocated.
malloc reference
strtol
long int strtol(const char *str, char **endptr, int base);
strtol returns a long int (which in the code above is casted to an int). It splits str into three parts:
Any white-space preceding the numerical content of the string
The part it recognises as numerical, which it will try to convert
The rest of the string
If endptr is not NULL, it will point to the 3rd part, so you know where strtol finished. You could use it like this:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char * endptr = NULL, *str = " 123some more stuff";
int number = strtol(str, &endptr, 10);
printf("number interpreted as %d\n"
"rest of string: %s\n", number, endptr);
return EXIT_SUCCESS;
}
output:
number interpreted as 123
rest of string: some more stuff
strtol reference
This is because the previous newline character left in the input stream by scanf(). Note that fgets() stops if it encounters a newline too.
fgets() reads in at most one less than size characters from stream and
stores them into the buffer pointed to by s. Reading stops after an
EOF or a newline. If a newline is read, it is stored into the
buffer
Don't mix fgets() and scanf(). A trivial solution is to use getchar() right after scanf() in order to consume the newline left in the input stream by scanf().
As per the documentation,
The fgets() function shall read bytes from stream into the array
pointed to by s, until n-1 bytes are read, or a < newline > is read and
transferred to s, or an end-of-file condition is encountered
In case of scanf("%d",&question_no); a newline is left in the buffer and that is read by
fgets(question[track-1],sizeof(question[track-1]),stdin);
and it exits.
In order to flush the buffer you should do,
while((c = getchar()) != '\n' && c != EOF)
/* discard */ ;
to clear the extra characters in the buffer

Resources