Create char array of integer using digits as size - c

I am trying to create a char array in C, to fill it with the digits of an int, but the int can be of any number of digits.
I'm using a created function called getDigits(int num), that returns a number of digits the int has.
char buffer[getDigits(number)] = "";
snprintf(buffer, sizeof(buffer),"%d",number);
but when I compile using gcc, it returns:
error: variable-sized object may not be initialized
I've tried everything. When I declare it as char fileSizeStr[5] = "";, it works. I can see the problem is rising when I try to declare the buffer size dynamically, but I would really like to know if is a way of achieving this.

The problem is exactly as your compiler is telling you; you're not allowed to initialise VLAs. Zack gave an obvious solution in the comments: Remove the initialisation. You'll find working examples in this answer, some of which do permit an initialisation, and others which don't. You'll find more information about that in comments. The following examples are ordered from most sensible (IMHO) to least sensible (which involve using malloc) for allocating storage for decimal digit sequences representing numbers.
I suggest using the same trick to determine how many bytes are necessary to store an int value as decimal digits as you'd use for octal: Divide the total number of bits in an int by 3 and add for any sign and NUL termination. digit_count could be written as a preprocessor macro like so:
#include <limits.h>
#include <stddef.h>
#include <stdio.h>
#define digit_count(num) (1 /* sign */ \
+ sizeof (num) * CHAR_BIT / 3 /* digits */ \
+ (sizeof (num) * CHAR_BIT % 3 > 0)/* remaining digit */ \
+ 1) /* NUL terminator */
int main(void) {
short short_number = -32767;
int int_number = 32767;
char short_buffer[digit_count(short_number)] = { 0 }; /* initialisation permitted here */
char int_buffer[digit_count(int_number)];
sprintf(short_buffer, "%d", short_number);
sprintf(int_buffer, "%d", int_number);
}
As you can see, one powerful benefit here is that digit_count can be used for any type of integer without modification: char, short, int, long, long long, and the corresponding unsigned types.
One minor downside by comparison is that you waste a few bytes of storage, particularly for small values like 1. In many cases, the simplicity of this solution more than makes up for this; The code required to count the decimal digits at runtime will occupy more space in memory than is wasted here.
If you're prepared to throw away the simplicity and generic qualities of the above code, and you really want to count the number of decimal digits, Zacks advice applies: Remove the initialisation. Here's an example:
#include <stddef.h>
#include <stdio.h>
size_t digit_count(int num) {
return snprintf(NULL, 0, "%d", num) + 1;
}
int main(void) {
int number = 32767;
char buffer[digit_count(number)]; /* Erroneous initialisation removed as per Zacks advice */
sprintf(buffer, "%d", number);
}
In response to the malloc recommendations: The least horrible way to solve this problem is to avoid unnecessary code (eg. calls to malloc and later on free). If you don't have to return the object from a function, then don't use malloc! Otherwise, consider storing into a buffer provided by the caller (via arguments) so that the caller can choose which type of storage to use. It's very rare that this isn't an appropriate alternative to using malloc.
If you do decide to use malloc and free for this, however, do it the least horrible way. Avoid typecasts on the return value of malloc and multiplications by sizeof (char) (which is always 1). The following code is an example. Use either of the above methods to calculate the length:
char *buffer = malloc(digit_count(number)); /* Initialisation of malloc bytes not possible */
sprintf(buffer, "%d", number);
... and don't forget to free(buffer); when you're done with it.

try something like:
char* buffer =(char *)malloc(getDigits(number)*sizeof(char));
malloc and calloc are used to dinamic allocation.

For my money, there is one solution which has gone unmentioned but which is actually simpler than any of the above. There is a combined allocating version of sprintf called "asprintf" available on Linux and most BSD variants. It determines the necessary size, mallocs the memory, and returns the filled string into the first argument.
char * a;
asprintf(&a, "%d", 132);
// use a
free(a);
Using a stack allocated array certainly removes the need for the free, but this completely obviates the need to ever separately calculate the size.

below may help
char* buffer;
buffer = (char*)malloc(number * sizeof(char));

You'll need to use malloc to allocate a dynamic amount of memory.
Initializing the way you did is allowed only if the size is known at compile time.

Related

How do I create a global string variable, set it somewhere, and fputs it to a file?

I'm new to the C language although I hear its very similar to c++ since c++ is kind of an add on to C?
I can't seem to get a global variable (empty string) to be set in a method and then printed to a text file.
I've tried a few things, but based on what seems to make sense and worked for me in other parts of my program.. this is where I'm at:
char fileReqName[1024] = "";//trying to create the global variable
//code lines and methods
//theres a pointer that point's to a "token" thats a string.. called pptr
strncpy(fileReqName, pptr, sizeof(pptr));
//in another method:
fputs(fileReqName,file_ptr);
But it's not working.
It's supposed to be getting a "filename" from a browser request. Sometimes it's cutting the name of the file the browser goes to into a smaller string and sometimes its not displaying anything. It could be a problem with the token, but when I was displaying it before, the token was always correct.
I also just tried:
strcpy(fileReqName, pptr);
which seems to work sometimes as well haha. I think I might have to check the other code for why it's not displaying the correct string/path?
Any suggestions? Thanks
If pptr is a pointer, sizeof(pptr) is probably 4 bytes. That would copy 4 bytes into fileReqName. You need to copy the length of the string, not just sizeof(pptr) (something like strlen(pptr)).
From the man page of strncpy:
char * strncpy ( char * destination, const char * source, size_t num );
Where:
num
Maximum number of characters to be copied from source.
size_t is an unsigned integral type.
Here you are using sizeof(pptr) instead of strlen(pptr). Take a look at this simple example:
#include <stdio.h>
int main(void) {
char * pptr = "this is a string literal";
printf("pptr = '%s', sizeof(pptr) = %ld, strlen(pptr) = %d",
pptr,sizeof(pptr),strlen(pptr));
}
Output:
pptr = 'this is a string literal', sizeof(pptr) = 8, strlen(pptr) = 24
strncpy copies n characters from the second parameter to the first... If the length of the second parameter is more than n you are no copying the null terminator... If you do strlen(pptr) you get the length of the string without the null terminator too!... then you will get some unpredictable results trying to use fileReqName in other functions like fputs(). You need to try:
strncpy(fileReqName, pptr, (strlen(pptr) + 1));
but it's the same as strcpy do...
I disagree with the 3 posted answers and submit another solution. The primary use of the n parameter is to insure the destination s1 is not overrun.
// prototype
#include <string.h>
char *strncpy(char * restrict s1, const char * restrict s2, size_t n);
// Recommended usage for OP
char fileReqName[1024];
fileReqName[sizeof(fileReqName) - 1] = '\0';
...
strncpy(fileReqName, pptr, sizeof(fileReqName) - 1);
This will perform the usual strcpy() function with 2 added prevention features.
1 Even if strlen(pptr) is 1023 or more, only the first 1023 are written, preventing a buffer overwrite.
2 Should #1 occur, the \0 assignment will insure fileReqName ends with a \0.
The first solution suggested strlen(pptr). This creates all sorts of issues as the \0 byte is not copied to fileReqName, leaving it potential unterminated. It does not prevent overruns.
The problem with strncpy(fileReqName, pptr, (strlen(pptr) + 1)) is that is does not prevent buffer overrun in fileReqName. Really no different than strcpy(fileReqName, pptr).
The printf() solution describes well the issues in the OP's trial solution, but does not supply what the OP should do.

Are there any practical differences between constructing a string via strdup() and malloc()?

Suppose I want to write a function that will produce a string, and while I can set an upper limit on the size of the string I don’t know in advance exactly how much space the string will take up. I can think of two ways to arrange this:
char *ParametersAsString_1(int temperature, float pressure)
{
char buffer1[128];
snprintf(buffer1, 128, "temperature: %d; pressure: %g",
temperature, pressure);
return strdup(buffer1);
}
char *ParametersAsString_2(int temperature, float pressure)
{
char *buffer2 = malloc(128);
snprintf(buffer2, 128, "temperature: %d; pressure: %g",
temperature, pressure);
return buffer2;
}
The only difference I can see is that the second form will potentially waste a bit of memory: it uses 128 bytes for buffer2 for that variable’s entire existence. The first function uses 128 bytes for buffer1 plus whatever memory the string “actually” uses, but when buffer1 is removed from the stack the only memory that will be used is whatever the string actually needs.
It looks like the first function would be better if the strings are long-lived and there will be a bunch of them. Are there any other reasons to prefer one of these forms over the other? (This is an academic question; I’m not actually in a situation where using an extra 90 bytes makes a difference.)
If you are looking for minimum memory usage not knowing the length beforehand, the solution lies in a special usage of snprintf. From the C11 standard:
7.21.6.5
2. .. If n is zero, nothing is written, and s may be a null pointer...
3. The snprintf function returns the number of characters that would have been written
had n been sufficiently large, not counting the terminating null character, or a negative
value if an encoding error occurred...
This means that if you write:
int size = snprintf(NULL, 0, "format string", arguments);
you will either get a negative value showing error (unlikely) or a positive value saying what would the ultimate size of the string be, without actually writing that string anywhere.
Therefore:
int size = snprintf(NULL, 0, "temperature: %d; pressure: %g", temperature, pressure);
/* error checking */
char *str = malloc((size + 1) * sizeof(*str));
/* error checking */
sprintf(str, "temperature: %d; pressure: %g", temperature, pressure);
return str;
Note that strdup and asprintf are not standard. The former is a POSIX extension and the later is a GNU extension.
This solution will give you an unbounded string, so it's quite useful (you don't have to cut the string). However, if you do want to cut the string, simply allocate a smaller memory if size was too big and use snprintf with the proper size to create the (cut) string in the buffer.
If you want to be more secure and future proof as well as avoid repeating code, you can use a macro:
#define YOUR_LIB_YOUR_FUNC_NAME_SNPRINTF(s, n) \
snprintf(s, n, "temperature: %d; pressure: %g", \
temperature, pressure)
int size = YOUR_LIB_YOUR_FUNC_NAME_SNPRINTF(NULL, 0);
/* error checking */
char *str = malloc((size + 1) * sizeof(*str));
/* error checking */
YOUR_LIB_YOUR_FUNC_NAME_SNPRINTF(str, size + 1)
return str;
#undef YOUR_LIB_YOUR_FUNC_NAME_SNPRINTF
In fact, modifying this function a little bit to work with vsnprintf, you get an implementation of asprintf that you could use wherever needed.
You can also use asprintf. buffer will be allocated with the needed size... (This pointer should be passed to free() to release the allocated storage when it is no longer needed)
char* ParametersAsString_3(int temp, float pres) {
char* buffer;
asprintf(&buffer, "temperature: %d; pressure: %g", temp, pres);
return (buffer);
}
As to the question in title: strdup() uses malloc(). It means that after strdup you should use free().
As to the examples, the second function allocates memory without freeing, the first not, so forget the second. Still, for the first function, you should free the functions result once you don't need it.
EDIT: the question was edited, so the answer must be edited too :)
Before the question was edited, the second function ended with strdup(buffer2). I meant in my answer, that the second function leacks memory allocated for buffer2. Both functions, as they were then, returned address that should be freed afterwards, but the second would cause additional leack.
strdup calls malloc and memcpy internally. So Function 1 has extra cost of calling memcpy function.
So Function 2 looks better option considering this reason along with reasons specified by #shahbaz.

Creating C substrings: looping with assignment operator VS strncopy, which is better?

This might be somewhat pointless, but I'm curious what you guys think about it. I'm iterating over a string with pointers and want to pull a short substring out of it (placing the substring into a pre-allocated temporary array). Are there any reasons to use assignment over strncopy, or vice-versa? I.e.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{ char orig[] = "Hello. I am looking for Molly.";
/* Strings to store the copies
* Pretend that strings had some prior value, ensure null-termination */
char cpy1[4] = "huh\0";
char cpy2[4] = "huh\0";
/* Pointer to simulate iteration over a string */
char *startptr = orig + 2;
int length = 3;
int i;
/* Using strncopy */
strncpy(cpy1, startptr, length);
/* Using assignment operator */
for (i = 0; i < length; i++)
{ cpy2[i] = *(startptr + i);
}
/* Display Results */
printf("strncpy result:\n");
printf("%s\n\n", cpy1);
printf("loop result:\n");
printf("%s\n", cpy2);
}
It seems to me that strncopy is both less typing and more easily readable, but I've seen people advocate looping instead. Is there a difference? Does it even matter? Assume that this is for small values of i (0 < i < 5), and null-termination is assured.
Refs: Strings in c, how to get subString, How to get substring in C, Difference between strncpy and memcpy?
strncpy(char * dst, char *src, size_t len) has two peculiar properties:
if (strlen(src) >= len) : the resulting string will not be nul-terminated.
if (strlen(src) < len) : the end of the string will be filled/padded with '\0'.
The first property will force you to actually check if (strlen(src) >= len) and act appropiately. (or brutally set the final character to nul with dst[len-1] = '\0';, like #Gilles does above) The other property is not particular dangerous, but can spill a lot of cycles. Imagine:
char buff[10000];
strncpy(buff, "Hello!", sizeof buff);
which touches 10000 bytes, where only 7 need to be touched.
My advice:
A: if you know the sizes, just do memcpy(dst,src,len); dst[len] = 0;
B: if you don't know the sizes, get them somehow (using strlen and/or sizeof and/or the allocated size for dynamically allocced memory). Then: goto A above.
Since for safe operation the strncpy() version already needs to know the sizes, (and the checks on them!), the memcpy() version is not more complex or more dangerous than the strncpy() version. (technically it is even marginally faster; because memcpy() does not have to check for the '\0' byte)
While this may seem counter-intuitive, there are more optimized ways to copy a string than by using the assignment operator in a loop. For instance, IA-32 provides the REP prefix for MOVS, STOS, CMPS etc for string handling, and these can be much faster than a loop that copies one char at a time. The implementation of strncpy or strcpy may choose to use such hardware-optimized code to achieve better performance.
As long as you know your lengths are "in range" and everything is correctly nul terminated, then strncpy is better.
If you need to get length checks etc in there, looping could be more convenient.
A loop with assignment is a bad idea because you're reinventing the wheel. You might make a mistake, and your code is likely to be less efficient than the code in the standard library (some processors have optimized instructions for memory copies, and optimized implementations usually at least copy word by word if possible).
However, note that strncpy is not a well-rounded wheel. In particular, if the string is too long, it does not append a null byte to the destination. The BSD function strlcpy is better designed, but not available everywhere. Even strlcpy is not a panacea: you need to get the buffer size right, and be aware that it might truncate the string.
A portable way to copy a string, with truncation if the string is too long, is to call strncpy and always add the terminating null byte. If the buffer is an array:
char buffer[BUFFER_SIZE];
strncpy(buffer, source, sizeof(buffer)-1);
buf[sizeof(buffer)-1] = 0;
If the buffer is given by a pointer and size:
strncpy(buf, source, buffer_size-1);
buf[buffer_size-1] = 0;

One liner to find length of a variable

I just stumbled upon the idea that since printf returns the no.of characters it has printed to the output stream why not use it to find length of any variable in c?
The code goes something like this,
#include<stdio.h>
int main()
{
char *a="Length";
int i=1000;
printf("Size: %d\n",printf("%d\n",i)-1);
printf("String Size: %d",printf("%s\n",a)-1);
return 1;
}
Am I right? I am not concerned about where it is being used. just wanted to know if my understanding is right.
What do you mean by "length of any variable"? You mean the number of bytes used to store the variable (which better achieved with the sizeof and strlen functions) or the byte length of the string representation of the variables?
For the latter one, you should be careful, since you can use format options to actually modify the results. Consider the following example:
float num = 10.0f;
printf("%.10f", num); // return value should be 13
printf("%f", num); // return value depends on the implementation of printf and the float value supplied
Also you have to consider that there are other representations than the decimal one.
As others have already stated, printf has the side effect that it actually writes to stdout. If you do not want this, you can use snprintf to write to a buffer and not to stdout:
char buffer[256];
int x = 10;
snprintf(buffer, sizeof(buffer), "%d", x); // return value is '2'
"One liner to find length of a variable"
Not possible unless its builtin to your compiler, or you define a wild and hairy macro half a page long with a few enums to state your type...
For strings, (which you cannot use sizeof on...) see: https://stackoverflow.com/a/22128415/3370790

Convert numbers with toString in Ansi C

Is it possible to use toString operator, or how to convert numbers to char arrays.
int myNumber = 27; /* or what have you */
char myBuffer[100];
snprintf(myBuffer, 100, "%d", myNumber);
There are several considerations for you to think about here. Who provides the memory to hold the string? How long do you need it for, etc? (Above it's a stack buffer of 100 bytes, which is way bigger than necessary for any integer value being printed.)
Best answer: start using Java. Or Javascript, or C#, or for the love of God almost anything but C. Only tigers lie this way.
Use the sprintf() function.
sprintf() is considered unsafe because it can lead to a buffer overflow. If it's available (and on many platforms it is), you should use snprintf() instead.
Consider the following code:
#include <stdio.h>
int main()
{
int i = 12345;
char buf[4];
sprintf(buf, "%d", i);
}
This leads to a buffer overflow. So, you have to over-allocate a buffer to the maximum size (as a string) of an int, even if you require fewer characters, since you have the possibility of an overflow. Instead, if you used snprintf(), you could specify the number of characters to write, and any more than that number would simply be truncated.
#include <stdio.h>
int main()
{
int i = 12345;
char buf[4];
snprintf(buf, 4, "%d", i);
//truncates the string to 123
}
Note that in either case, you should take care to allocate enough buffer space for any valid output. It's just that snprintf() provides you with a safety net in case you haven't considered that one edge case where your buffer would otherwise overflow.

Resources