Best implementation of fgets size argument? - c

I've been comparing the two statements, which use fgets to read a string from standard input.
char array[10];
fgets(array, sizeof(array), stdin) ;
fgets(array, (sizeof(array)/sizeof(array[0])) , stdin);
Technically, both are identical, with the exception that method 2 is redundant, since fgets can only accept a char array.
My thought process is that since fgets takes a char *s argument there isn't any need for the second example(chars are one byte, so division by 1 is redundant) .
However, when dealing with arrays of a different data type (in a for loop for example), the second method of determining the size of the array is required.
The second statement looks ugly, but are there any other major disadvantages of using it? Here are some advantages I can think of:
Teaches correct way of determining array sizes for other applications, e.g. for for() loops.
Does not break down if (not applicable for this example, as fgets only takes char arrays) the array type is changed

The second form, shown below, could get you an unpleasant surprise.
fgets(array, (sizeof(array)/sizeof(array[0])) , stdin);
Specifically, the second argument to fgets represents the maximum number of char values (less 1 for the trailing NUL) which array can hold.
So, if array is declared as
char array[SOME_NUMBER];
Then sizeof(array)/sizeof(array[0]) would yield SOME_NUMBER. But what if it were defined as one of the following:
int array[SOME_NUMBER];
char array[SOME_NUMBER][SOME_OTHER_NUMBER];
In the both cases, it would yield SOME_NUMBER because it calculates the number of elements in the array. But it completely ignores the size of each element. Imagine in the second case that SOME_NUMBER was significantly larger than SOME_OTHER_NUMBER. The fgets would fill the first element of array and then overflow into one or more of the subsequent elements. Here you really wanted to pass in SOME_OTHER_NUMBER.
The take-away here is that you need to be explicit in the value you pass to fgets. For the normal case (a single-dimension char array), sizeof(array) is fine. For an array of char arrays (as shown above), then either SOME_OTHER_NUMBER or sizeof(array[0]) should be used.
The sizeof(array)/sizeof(array[0]) approach should never be used, because it is not calculating a size which inherently relates to sizeof(char). It is calculating the number of elements in array - regardless of their size.

Related

Checking if an array has at least 3 elements

I'm not sure how to approach this but put simply, a part of my homework states that I need to check if an array has at least 3 stored integer values and display an error message if it has less. The other part is getting the sum of all values in the array and show the output in the console.
I'm using RARS and the array is already declared in .data along with its values.
Arrays have a notion of length, which can be in bytes, or in element count, but unlike Java and C#, there is no standardized way to represent this notion of length in assembly language or in C code.
Sometimes the length is represented in the program by a constant.
Sometimes the length is represented in the program by a variable, more or less directly as a count of elements (though a program variable could also be an index referring to the last element, in which case that count is that variable + 1).
Sometimes the length is represented in the program by an end pointer — a pointer one element past the last, and also the place to store the next element, if one comes, when growing the array in place is possible.
Sometimes the length is encoded as a special element value, a sentinel or terminator, and to find the length one traverses forwards until that element is found — there must be sufficient storage to hold the real elements and the sentinel as well but it not considered an element of the array.
C-style strings are arrays of character, nul-terminated, so use the special character nul aka `\0' or just 0 as the terminator.
We can also pair a length value with a pointer value to compose a higher level notion of array with length into an object or structure.
This is not necessarily a complete list, since programmers can do as they like.  (Other schemes are possible, such as storing the length at the beginning of the array, or in front of the array, i.e. at position -1 in the array).
A function taking an array as a parameter will often also take another parameter that is the length, but in the case of int main(int argc, char *argv[]) we see the length being passed as the first parameter and the array as the second..
It would be a logic error for a program to have an array whose length is unknown and not computable.
You will need to determine the method for representing the length, and then compare the length with your constant 3 as required.
For example, if the method is an end pointer, then you can subtract: end pointer - beginning pointer (the array base, or address of first element), and then divide that result by the array's element size, which will yield a count of the number of elements.

Does specifying array size for a user input string in C matter?

I am writing a code to take a user's input from the terminal as a string. I've read online that the correct way to instantiate a string in C is to use an array of characters. My question is if I instantiate an array of size [10], is that 10 indexes? 10 bits? 10 bytes? See the code below:
#include <stdio.h>
int main(int argc, char **argv){
char str[10] = "Jessica";
scanf("%s", &str);
printf("%c\n", str[15]);
}
In this example "str" is initialized to size 10 and I am able to to print out str[15] assuming that when the user inputs a a string it goes up to that index.
My questions are:
Does the size of the "str" array increase after taking a value from scanf?
At what amount of string characters will my original array have overflow?
.
When you declare an array of char as you have done:
char str[10] = "Jessica";
then you are telling the compiler that the array will hold up to 10 values of the type char (generally - maybe even always - this is an 8-bit character). When you then try to access a 'member' of that array with an index that goes beyond the allocated size, you will get what is known as Undefined Behaviour, which means that absolutely anything may happen: your program may crash; you may get what looks like a 'sensible' value; you may find that your hard disk is entirely erased! The behaviour is undefined. So, make sure you stick within the limits you set in the declaration: for str[n] in your case, the behaviour is undefined if n < 0 or n > 9 (array indexes start at ZERO). Your code:
printf("%c\n", str[15]);
does just what I have described - it goes beyond the 'bounds' of your str array and, thus, will cause the described undefined behaviour (UB).
Also, your scanf("%s", &str); may also cause such UB, if the user enters a string of characters longer than 9 (one must be reserved for a terminating nul character)! You can prevent this by telling the scanf function to accept a maximum number of characters:
scanf("%9s", str);
where the integer given after the % is the maximum input length allowed (anything after this will be ignored). Also, as str is defined as an array, then you don't need the explicit "address of" operator (&) in scanf - it is already there, as an array reference decays to a pointer!
Hope this helps! Feel free to ask for further clarification and/or explanation.
One of C's funny little foibles is that in almost all cases it does not check to make sure you are not overflowing your arrays.
It's your job to make sure you don't access outside the bounds of your arrays, and if you accidentally do, almost anything can happen. (Formally, it's undefined behavior.)
About the only thing that can't happen is that you get a nice error message
Error: array out-of-bounds access at line 23
(Well, theoretically that could happen, but in practice, virtually no C implementation checks for array bounds violations or issues messages like that.)
See also this answer to a similar question.
An array declares the given number of whatever you are declaring. So in the case of:
char str[10]
You are declaring an array of ten chars.
Does the size of the "str" array increase after taking a value from scanf?
No, the size does not change.
At what amount of string characters will my original array have overflow?
An array of 10 chars will hold nine characters and the null terminator. So, technically, it limits the string to nine characters.
printf("%c\n", str[15]);
This code references the 16th character in your array. Because your array only holds ten characters, you are accessing memory outside of the array. It's anyone's guess as to if your program even owns that memory and, if it does, you are referencing memory that is part of another variable. This is a recipe for disaster.

C char array and \0

In C, if I initialize a char array like this:
char lines[5];
memcpy((char *)line,"Hello",5)
Then if I execute the following expression:
line[6]='\0';
Would this cause buffer overflow? Thanks?
Many problems. For one, why cast to char *, when that is to what the array decays? Second, you need to use a zero-based index, not a one-based index; The first element of array a is a[0] not a[1].
Also you should have set the buffer size to 6, not 5, to make room for terminator
Then if I execute the following expression:
line[6]='\0';
Would this cause buffer overflow?
Yes. Because lines contains five characters and you are overwriting the seventh one.
Would the comp[il]er assign 8 bytes for 'lines'?
No.
It might put 3 bytes of padding after lines, in which case it's still a buffer overflow because lines is still 5 bytes long.
You are definitely writing outside the bounds of the array, which leads to undefined behavior. The result could be any of the following:
a runtime error (segfault);
corrupted data (overwriting part of another object);
behaving exactly as expected
Most platforms have alignment requirements such that there may be some unused bytes between the end of the array and the next object in memory1, and writing one or two bytes past the end of the array isn't much of an issue. But that's not the same thing as the compiler allocating "extra space" for the array.
Assuming the array size isn't a multiple of 2 or 4 bytes, anyway.

Print only the rightmost part of a string

I am applying printf and/or other functions to a certain string of characters, read from a file. I want to skip the first 5 characters under certain conditions. Now I thought to be clever by, if the conditions apply, increasing the string pointer by 5:
if (strlen(nav_code) == 10 ) {nav_code = 5+nav_code;}
but the compiler refuses this:
error: assignment to expression with array type
What have I misunderstood? How to make my idea work - or is it a bad idea anyway?
It's probably becuase nav_code is not a pointer but a character array like char nav_code[50]. Try the following:
char nav_code[50];
char *nav_code_ptr = nav_code;
if (strlen(nav_code_ptr) == 10 ) {nav_code_ptr += 5;}
// forth on, use nav_code_ptr instead of nav_code
I am applying printf and/or other functions to a certain string of characters, read from a file. I want to skip the first 5 characters under certain conditions.
If printf is all what you need, then sure you can skip the first 5 characters.
Given nav_code is string (either char array or char pointer), then:
printf( "%s", nav_code + 5 ); // skip the first 5 characters
Of course you need to make sure your string has more than 5 characters, otherwise it's flat out illegal as out-of-bound access.
In your code, nav_code is an array and arrays cannot be assigned.
Instead, use a pointer, initialize that with the address of the first element of the array, make pointer arithmetic on that pointer and store the updated result back to the pointer.

what will be happen to the size of string in this code?

#include <stdio.h>
#include <stdlib.h>
int main()
{
int size=10;
char string1[50];
char *string2;
string2=(char *)malloc(size*sizeof(char));
fgets(string1,10,stdin);
printf("%s",string1);
fgets(string2,10,stdin);
printf("%s",string2);
}
There are two strings in this code one is an array and another one is dynamically created using pointer.
If my input is less than 50 for string1 and less than 10 for string2 will the space that is not filled get wasted ,if so how to reduce the size.
In case of string 2 malloc size parameter is 10 and fgets size parameters is 10 what will happen if i increase the size to fgets(string2,50,stdin) which is greater than malloc's size?
how to calculate the final size of input string in each case?I have used sizeof operator but it gave the hardcoded size that is 50 and 10 respectively for string1 and string2
Is there any other better approach to create a dynamic string?
Yes, it will be wasted. You can use variable-length arrays to use a different limit, or use dynamic allocation. Whether or not you should worry about the wasted space is a separate question: if your program reads strings that the user inputs manually (as opposed to reading a file) you can waste a lot of space before it starts to matter, unless you are on an embedded system with severe memory constraints.
You will get undefined behavior, so your program will be invalid. Don't do that - it is precisely why fgets takes the maximum length of the string.
Call strlen to compute the length of the string. Add 1 for null terminator. Remember that '\n' is part of the string when you use fgets and the input has '\n' in it.
You can use POSIX extension to scanf, and pass %ms format and a pointer to char*. This will allocate the string at the exact length, but your program will be less portable. Obviously, you are required to deallocate these strings to avoid memory leaks.

Resources