This question already has answers here:
sprintf buffer sizes
(3 answers)
Closed 9 years ago.
I'm having an issue with sprintf in C resetting the value of a counter variable when I run it. Here in a nutshell is what is happening:
int count = 0;
count++;
printf("%d\n", count); // count will equal 1
char title[7];
sprintf(title, "%.3d.jpg", count);
printf("%d\n", count); // count now equals 0 again
Is this normal behavior for sprintf?
title is too small, sprintf is writing beyond the bounds of title, and writing into count, corrupting its value.
Note that title needs to be long at least 8 bytes: 3 for %.3d, 4 for .jpg and 1 for the terminator \0.
As Grijesh Chauhan points out, you can make sure that you never write beyond the allocated size of the string by using snprintf, i.e.:
char title[8];
snprintf(title, sizeof(title), "%.3d.jpg", count);
You simply need more space in the string title: 3 digits+".jpg" = 7 chars, and u need one extra for '\0'(end of the string). Sprintf can change argument in a case such as this(Using sprintf will change the specified variable)
Solution: change
char title[7];
to
char title[8];
You problem is called buffer overflow. sprintf has no idea of the size of title, and write has much as needed, even if it exceeds the boundaries of your array. To fully understand, you also have to know that strings are terminated by a zero. This allows to find the end of a string, without prior knowledge of its true size. This extra zero takes the place of an extra character that you have to consider when dimensioning your buffers.
Consider also the use of snprintf that ensures you are not going over the boundaries of your buffer.
Related
I'm working with char arrays in C. I'm setting the size in a previous step. When I print it out it clearly shows the num_digits as 1.
But then when I put it in to set the size of a char array to make it a char array of size num_digits, its setting the size of the array as 6.
In the next step when I print strlen(number_array), it prints 6. Printing it out I get something with a lot of question marks. Does anyone know why this is happening?
int num_digits = get_num_digits(number);
printf("Num digits are %d\n", num_digits);
char number_array[num_digits];
printf("String len of array: %d\n", strlen(number_array));
You need to null terminate your array.
char number_array[num_digits + 1];
number_array[num_digits] = '\0';
Without this null terminator, C has no way of know when you've reached the end of the array.
just use 'sizeof' instead of 'strlen'
printf("String len of array: %d\n", sizeof(number_array));
There are a couple possible issues I see here:
As noted in Michael Bianconi's answer, C character arrays (often called strings) require null terminators. You would explicitly set this this with something like:
number_array[number + 1] = '\0'; /* See below for why number + 1 */
Rather than just setting the last element to null, pre-initializing the entire character array to nulls might be helpful. Some compilers may do this for you, but if not you'll need to do this explicitly with something like:
for (int i = 0; i < num_digits + 1; i ++) number_array[i] = '\0';
Note that with gcc I had to use C99 mode using -std=c99 to get this to compile, as the compiler didn't like the initialization within the for statement.
Also, the code presented sets the length of the character array to be the same length as number's length. We don't know what get_num_digits returns, but if it returns the actual number of significant digits in an integer, this will come up one short (see above and other answer), as you need an extra character for the null terminator. An example: if the number is 123456 and get_number_digits returns 6, you would would need to set the length of number_array to 7, instead of 6 (i.e. number + 1).
char number_array[num_digits]; allocates some space for a string. It's an array of num_digits characters. Strings in C are represented as an array of characters, with a null byte at the end. (A null byte has the value zero, not to be confused with the digit character '0'.) So this array has room for a string of up to num_digits - 1 characters.
sizeof(number_array) gives you the array storage size. That's the total amount of space you have for a string plus its null terminator. At any given time, the array can contain a string of any length up to number_array - 1, or it might not contain a string at all if the array doesn't contain a null terminator.
strlen(number_array) gives you the length of the string contained in the array. If the array doesn't contain a null terminator, this call may return a garbage value or crash your program (or make demons fly out of your nose, but most computers fortunately lack the requisite hardware).
Since you haven't initialized number_array, it contains whatever happened to be there in memory before. Depending on how your system works, this may or may not vary from one execution of the program to the next, and this certainly does vary depending on what the program has been doing and on the compiler and operating system.
What you need to do is:
Give the array enough room for the null terminator.
Initialize the array to an empty string by making setting the first character to zero.
Optionally, initialize the whole array to zero. This is not necessary, but it may simplify further work with the array.
Use %zu rather than %d to print a size. %d is for an int, but sizeof and strlen return a size_t, which depending on your system may or may not be the same size of integers.
char number_array[num_digits + 1];
number_array[0] = 0; // or memset(number_array, 0, sizeof(number_array));
printf("Storage size of array: %zu\n", sizeof(number_array));
printf("The array contains an empty string: length=%zu\n", strlen(number_array));
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I declared a character pointer, and used it for to scan a string in runtime; I don't know the number of characters that I'm going to enter, so I didn't use calloc or malloc. The program ends when it reached the line scanf("%s", NewMsg_au8).
I'm using CodeBlocks 17.12 editor.
I tried hard coding one of the input case like, NewMsg_au8="0123456789ABCDEF"; — that works fine.
uint8 * NewMsg_au8;
scanf("%s",NewMsg_au8);//<==
printf("Your entered message is: %s\n",NewMsg_au8);
return NewMsg_au8;
gets(s) and scanf("%s", s) are both unsafe and potentially incorrect because:
with those calls as shown, there is no way for either function to determine the maximum number of characters to store into the array pointed to by s, hence overlong input will cause a buffer overrun leading to undefined behavior.
in your case, it is even worse as s is an uninitialized pointer, so both functions would try a store data into a random address in memory causing undefined behavior in all cases.
gets() cannot be used safely and has been deprecated in and then removed from the C Standard.
However, scanf() can be given a limit with a numeric value between % and s:
#include <stdio.h>
#include <string.h>
char *read_string(void) {
char buf[100];
if (scanf("%99s", buf) == 1) {
printf("Your entered message is: %s\n", buf);
return strdup(buf); /* return an allocated copy of the input string */
} else {
/* no input, probably at end of file */
return NULL;
}
}
Note how only 99 characters can be stored into the array buf to allow for the null byte terminator that marks the end of a C string. The %99s conversion specification lets scanf() store at most 100 bytes into buf, including the '\0' terminator.
That is a typical beginners error. You do not save data in pointers (with gets() or scanf()) but in buffers.
Therefore, you have 2 solutions:
Use an array big enough to hold the data. You have to decide yourself what "big enough" means, according to the details of your application.
Use a pointer, and then allocate memory with malloc() - the size, again, you have to decide it. Do not forget to deallocate the memory when you no longer need it.
I tried hard coding one of the input case like, NewMsg_au8="0123456789ABCDEF"; — that works fine.
That is normal, because in that case the compiler automatically allocates enough memory to hold the string.
Please always remember when working with strings: you always need to allocate an extra byte for the terminating null character - the mark of the end of the string. Otherwise, you will need to ask questions again :)
This question already has answers here:
How do I determine the size of my array in C?
(24 answers)
Closed 6 years ago.
my professor has assigned a project where we need to make a reverse polish calculator in C (input in postscript syntax). I'm currently working on a method to find the length of the array of values I have scanned in (via .txt file). My current method is
int length(int list[]) {
int c = 0;
while(0 == 0) {
if(list[c] != '\0') {c++;}
else {break;}
}
return c;
}
and the call for it is
int sizeA = length(list);
printf("\n%d\n", sizeA);
It's currently only outputting the length as 0. Does anyone know why that might be and a fix to this method?
Thanks
The notion of "length" is a sort of tricky one in C (and low-level programming in general). If you have an array, the C compiler knows how large it is and provides an interface to the programmer to get that value in bytes: sizeof. The thing is, arrays are passed via pointers in C and determining the size via pointers is impossible without certain meta-information. Common methods to determine the length of an array are
appending an end marker to the array. Determining the length is simply a matter of iterating until the end marker is found and returning the number of iterations. Note that this renders the end marker's value unavailable for use as a value in the array.
just passing the size of the array around. Take the write system call as an example. Besides the file handle, it needs a pointer to the data and its length. Why its length as well? Because the pointer doesn't contain information about the length. So, either use a terminator like a null byte or pass the length explicitly. The former idea can be abandoned because the write system call is supposed to be generic; and to yield genericity, a null byte must be expected to be a possible value in the array, so it cannot be used as a terminator for reasons I uttered above.
Which one you actually end up using totally depends on the particular use case.
Apparently you decided to use the terminator-variant. \0 is the null byte, an ASCII character with code value 0x0. It's commonly used for terminating C-strings. strlen uses it to determine a C-string's length, for example. For int arrays, there is no such predefined terminator, so you need to come up with your own one. If you decide on \0, so be it, but I'd use the literal 0x0 instead because strictly-speaking, \0 is a character literal and that's just unfitting for ints.
To actually implement this, you'd need to append the terminating value to every int array, whose size you want to determine this way. Then write your function to get the length of such an int array just as you do, i.e., by iterating until the terminator is found.
I am using char array[6];
I am converting a float variable to string using sprintf as follows..
sprintf(array,"%f\0",floatvar);
and i am writing char array on LCD.
Problem is my array size is only 6 bytes, but it is printing "00000.00000" 11 byte of data. Array size is restricted to 6 bytes. But How the array overflowing in this case?
The sprintf function expects that you provide a big enough buffer to hold all of its output. Otherwise your code causes undefined behaviour.
Your code would not produce 00000.00000 either; if the value is between 0 and 1 then the output will start with 0. . Perhaps you used a different format string in your real code.
With %f it is not possible to constrain the output solely via format string modifiers. To be safe, you can use snprintf:
snprintf(array, 6, "%f", floatvar);
If your system does not have snprintf available then I would suggest downloading a freeware implementation of vsnprintf.
As a last resort you could use sprintf with a lot of checking:
if ( floatvar < 0.f || floatvar >= 1.f )
exit.....;
sprintf(array, 6, "%.3f", floatvar);
The .3 means that at most 3 characters will show after the decimal point; and since we did a range check that means the start will be 0. , for a total of 5 output characters plus null terminator.
To be on the safe side I'd suggest temporarily outputting to a large buffer, using strlen to check what was written, and then copying to your 6-byte buffer if it did write correctly.
NB. "%f\0" is strange; string literals are strings and so they end in '\0' already. "%f\0" ends in two null terminators.
Consider following case:
#include<stdio.h>
int main()
{
char A[5];
scanf("%s",A);
printf("%s",A);
}
My question is if char A[5] contains only two characters. Say "ab", then A[0]='a', A[1]='b' and A[2]='\0'.
But if the input is say, "abcde" then where is '\0' in that case. Will A[5] contain '\0'?
If yes, why?
sizeof(A) will always return 5 as answer. Then when the array is full, is there an extra byte reserved for '\0' which sizeof() doesn't count?
If you type more than four characters then the extra characters and the null terminator will be written outside the end of the array, overwriting memory not belonging to the array. This is a buffer overflow.
C does not prevent you from clobbering memory you don't own. This results in undefined behavior. Your program could do anything—it could crash, it could silently trash other variables and cause confusing behavior, it could be harmless, or anything else. Notice that there's no guarantee that your program will either work reliably or crash reliably. You can't even depend on it crashing immediately.
This is a great example of why scanf("%s") is dangerous and should never be used. It doesn't know about the size of your array which means there is no way to use it safely. Instead, avoid scanf and use something safer, like fgets():
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. A terminating null byte ('\0') is stored after the last character in the buffer.
Example:
if (fgets(A, sizeof A, stdin) == NULL) {
/* error reading input */
}
Annoyingly, fgets() will leave a trailing newline character ('\n') at the end of the array. So you may also want code to remove it.
size_t length = strlen(A);
if (A[length - 1] == '\n') {
A[length - 1] = '\0';
}
Ugh. A simple (but broken) scanf("%s") has turned into a 7 line monstrosity. And that's the second lesson of the day: C is not good at I/O and string handling. It can be done, and it can be done safely, but C will kick and scream the whole time.
As already pointed out - you have to define/allocate an array of length N + 1 in order to store N chars correctly. It is possible to limit the amount of characters read by scanf. In your example it would be:
scanf("%4s", A);
in order to read max. 4 chars from stdin.
character arrays in c are merely pointers to blocks of memory. If you tell the compiler to reserve 5 bytes for characters, it does. If you try to put more then 5 bytes in there, it will just overwrite the memory past the 5 bytes you reserved.
That is why c can have serious security implementations. You have to know that you are only going to write 4 characters + a \0. C will let you overwrite memory until the program crashes.
Please don't think of char foo[5] as a string. Think of it as a spot to put 5 bytes. You can store 5 characters in there without a null, but you have to remember you need to do a memcpy(otherCharArray, foo, 5) and not use strcpy. You also have to know that the otherCharArray has enough space for those 5 bytes.
You'll end up with undefined behaviour.
As you say, the size of A will always be 5, so if you read 5 or more chars, scanf will try to write to a memory, that it's not supposed to modify.
And no, there's no reserved space/char for the \0 symbol.
Any string greater than 4 characters in length will cause scanf to write beyond the bounds of the array. The resulting behavior is undefined and, if you're lucky, will cause your program to crash.
If you're wondering why scanf doesn't stop writing strings that are too long to be stored in the array A, it's because there's no way for scanf to know sizeof(A) is 5. When you pass an array as the parameter to a C function, the array decays to a pointer pointing to the first element in the array. So, there's no way to query the size of the array within the function.
In order to limit the number of characters read into the array use
scanf("%4s", A);
There isn't a character that is reserved, so you must be careful not to fill the entire array to the point it can't be null terminated. Char functions rely on the null terminator, and you will get disastrous results from them if you find yourself in the situation you describe.
Much C code that you'll see will use the 'n' derivatives of functions such as strncpy. From that man page you can read:
The strcpy() and strncpy() functions return s1. The stpcpy() and
stpncpy() functions return a
pointer to the terminating `\0' character of s1. If stpncpy() does not terminate s1 with a NUL
character, it instead returns a pointer to s1[n] (which does not necessarily refer to a valid mem-
ory location.)
strlen also relies on the null character to determine the length of a character buffer. If and when you're missing that character, you will get incorrect results.
the null character is used for the termination of array. it is at the end of the array and shows that the array is end at that point. the array automatically make last character as null character so that the compiler can easily understand that the array is ended.
\0 is an terminator operator which terminates itself when array is full
if array is not full then \0 will be at the end of the array
when you enter a string it will read from the end of the array