Most efficient way to use strcat() with a string and int? - c

I'm try to concatenate to char * rv with the result of a function call that will return an int. fib() returns an int. The main problem I'm running into is that strcat()'s signature requires a const char * as it's second arg:
char * strcat ( char * destination, const char * source );
Here is a small sample of my code. fib() calculates the nth fibonacci number - in this case, the 7th fibonacci number.
char * rv;
int num;
rv = (char*)malloc(2048*sizeof(char));
num = 7;
...
strcat(rv, (const char *)itoa(fib(num), rv,10));
Obviously this is wrong and won't compile. What is the cleanest way to do this? Do I need another char * var to store the results of itoa() first, instead of using rv?
Thank you for any help you can provide!

Use snprintf() to construct a buffer containing the int and then concatenate it to your rv buffer. Do not attempt to concatenate the existing content of rv in the same call to snprintf():
snprintf(rv, 2048, "%s%d", rv, itoa(fib(num), rv,10)));
as this means the input and output buffers overlap which is undefined behaviour.
Also:
sizeof(char) is guaranteed to be 1
see Do I cast the result of malloc?
So the malloc() call would be:
rv = malloc(2048);
if (rv)
{
}

You need either an intermediate char array to print the number to before strcating, or you can directly sprintf the number to rv, but for that you need a pointer to the end,
char *rv = malloc(2048);
char *rv_end = rv;
...
rv_end += sprintf(rv_end, "%d", fib(num));
and also update the rv_end pointer when appending other things to the buffer.
(Thanks to jthill for the improvement using the return value of sprintf.)

You could do this
sprintf(dest,"%s %d",rv,num);

char * strcat ( char * destination, const char * source );
The "const" on source simply tells the compiler that the strcat function will not modify "source". Otherwise,
strcat(buffer, "hi");
would not be allowed.
This does not mean that your source must be constant, nor should it have the const modifier.
strcat(rv, (char *)itoa(fib(num), rv,10));
(no "const") is perfectly legal and should not generate any compiler warnings.
The only issue is that if you don't know the length of the source, you're opening yourself up to a buffer overflow. In this particular case, you can figure out how long the itoa return can be and size the destination accordingly. However, it's probably safer to us snprintf to control how large it is.

Related

How to join characters?

#include <stdio.h>
#include <string.h>
int main(void) {
char rez[100] = "\0";
char t = 97;
char temp;
strcpy(temp, t);
strcat(rez, temp);
printf("%s", rez);
return 0;
}
I want to join the character 'a' to the result but strcpy and strcat command do not work.
How could I do that if the char t should be an ASCII code?
warning: passing argument 1 of 'strcpy' makes pointer from integer without a cast [-Wint-conversion]
strcpy(temp,t);
note: expected 'char * restrict' but argument is of type 'char'
char * __cdecl strcpy(char * restrict _Dest,const char * restrict _Source);
Both functions work with strings, not with individual characters. It’s often convenient to create a new string of length 1 from the char, and work with that:
char str[] = { t, '\0' };
Now you can concatenate that.
Alternatively, you can implement the concatenation manually by just writing the character into the right location of the resulting array:
const len = strlen(rez);
rez[len] = t;
rez[len + 1] = '\0';
… or you could use the sprintf function:
sprintf(rez, "%s%c", rez, t);
In all cases you need to take care to not accidentally write outside of the bounds of the string.
In your specific case, none of these make sense, since rez is empty to start with; you’re not concatenating anything, you’re just writing a single character into a buffer.
rez[0] = t;
rez[1] = '\0'; // for good measure
strcpy and strcat expect both of their arguments to have type char * and that both arguments point to the first character of a zero-terminated string.
The problem is that neither t nor temp are pointers, and neither are the first characters of a string so passing &t or &temp will work.
If you want to append a single character to rez, you can do something like
/**
* Use character literals instead of raw ASCII codes -
* it’s easier to understand, it will work as expected
* on non-ASCII systems, and you’re less likely to make
* a mistake.
*/
t = 'a';
size_t len = strlen(rez);
/**
* Overwrite the terminator with the value in t,
* then write the terminator to the following element
* (strictly not necessary in this case, but it never
* hurts to make sure)
*/
rez[len++] = t;
rez[len] = 0;
You could also use the sprintf library function:
sprintf( rez, "%s%c", rez, t );

Is it possible to create a default value for an argument in a function with C?

Alright, so forgive me. I've started learning C, and coming from PHP, I hate the lack of explode() so I decided to create my own.
Here's what I have so far:
#include <stdio.h>
#include <windows.h>
char * explode(char * toExplode, char * delimiter) /* Need to add a buffer size here */
{
char * token;
token = strtok(toExplode, delimiter);
token = strtok(NULL, delimiter);
return token;
}
int main(void)
{
char string[] = "This is a string yaaaaay";
char * exploded;
exploded = explode(string, " ");
printf("%s\n", exploded); /* Should currently return 'is' */
return 0;
}
So far, it's working just as I expect it to. However, now I need to create a 2D array of variable size in the first dimension (actually, both dimensions.)
I was thinking of doing something like char * explode(char * toExplode, char * delimiter, int length = strlen(toExplode)) so that I could either specify the length or have it set it default. This of course doesn't work though, and I have no idea where to go from here.
Any ideas/help?
You can pass a known bad value (commonly a 0 or -1) as the length, have multiple similar functions, or use a macro.
If you go the bad value route, when you call your function you can give it a value you know isn't possible and check for such a bad value at the start of the function. Then automatically calculate the correct value and continue as usual. The problem with this is that you are now forced to have at least one bad value (not a problem in this case).
char * explode(char * toExplode, char * delimiter, int length){
if(length == 0)
length = ...;
In the multiple similar functions method, each function has a slightly different declaration. They cannot all have the same name because C does not support overloading the way that another language like C++ has. The printf() family of functions is a good example of this.
char * explodel(char * toExplode, char * delimiter, int length);
char * explode (char * toExplode, char * delimiter){
int length = ...;
return explodel(toExplode, delimiter, length);
}
The macro method is a bit of a hack, but it does work. It is a bit of a combination of the previous two methods, in which you have the two different functions you can call, but the first one gets preprocessed with a bad value automatically being passed to the other so it can figure out the correct length value.
#define explode (s, ...) explodel(s, __VA_ARGS__, 0)
char * explodel(char * toExplode, char * delimiter, int length, ...);
The way this works is that if you only give it the first two arguments, the 0 fall into place as the third argument. If you give it three arguments, all three are passed normally and the 0 is added as a forth invisible argument hidden away in the function stack. If you pass more than three, all the extra arguments will be hidden like the 0. If you try to pass only one argument, you will get the following error:
error: expected expression before ',' token
No you can't but that doesn't stop you from pushing in a dummy value (i.e. -1) and then first thing in the function if the value is -1 then change it to whatever value you want.
If you're stuck using C then the solution I'd recommend is rolling two functions; one with length, one without.
char * explode(char * toExplode, char * delimiter, int length)
{
...
}
char * explode(char * toExplode, char * delimiter)
{
int len = strlen(toExplode);
return explode(toExplode, delimiter, len);
}
So, the latter just works out the length for you and passes it to the former and returns the result.
In C you can't.
This is possible in C++, but with a constant value (-1), for example.
You can't overload a function in C, neither have default arguments, that's C++.
The only solution I can think of is having an static local variable, with the default value.
char * explode(char * toExplode, char * delimiter,unsigned int plen) /* Need to add a buffer size here */
{
static unsigned int slen = 100;
unsigned int len;
char * token;
if (plen!=0)
len = plen;
else
len = slen;
/*...*/
}

Can the following be made simpler / more efficient?

I'm trying to convert some code from a dynamic-typed language to C. Please
bear with me as I have no practical experience yet with C.
I have a dispatcher function that decides how to convert it's input based on
the value of the flag argument.
void output_dispatcher(char *str, int strlen, int flag) {
char output[501];
char *result;
switch (flag) {
/* No conversion */
case 0:
result = str;
break;
case 1:
result = convert_type1(output, str, strlen);
len = strlen(result);
break;
/* ... */
}
/* do something with result */
}
I currently have 5 different output converters and they all (even future
ones) are guaranteed to only produce 300-500 characters. From my reading, it
is preferable to use a heap variable than dynamically allocate space on the
stack, if possible. The function declaration for one looks like:
static char * convert_type1(char *out, const char *in, int inlen);
I want to avoid the strlen in the dispatcher, since it is uncessary to
recalculate the output size because the output converters know it when they
construct the output. Also, since I'm passing in a pointer to the output
variable, I shouldn't need to return the result pointer, right? So I modify
it to the following, but get an 'incompatible type' compilation error.
void output_dispatcher(char *str, int strlen, int flag) {
char output[501];
switch (flag) {
/* No conversion */
case 0:
output = str; /* ERROR: incompatible type */
break;
case 1:
strlen = convert_type1(output, str, strlen);
break;
/* ... */
}
/* do something with result */
}
Can this approach work, or is there a better way to go?
To avoid the recalculation your output converters would need to have a prototype like this:
static char * convert_type1(char *out, const char *in, int *len);
called thus:
result = convert_type1(output, str, &strlen);
Internally the output converter would need to read the contents of the pointer now containing the string length, and overwrite the contents of that pointer before returning.
On the issue of heap vs stack, indeed you need to use the heap since variables allocated on the stack will disappear as soon as the function ends.
The line:
output = str;
is giving you problems because, while arrays and pointers are similar, they're not the same.
"output" is an array, not a pointer.
str = output;
will work, because a char ptr is much like an array variable.
But the opposite does not because the "output" variable is not just the pointer to the array, but the array itself.
For example, if you had:
char output[501];
char output1[501];
and you did:
output1 = output;
This would be ok, and C would copy the contents of the output array in to the output1 array.
So, you're just a little confused about arrays and ptrs.
char output[501];
output = str; /* ERROR: incompatible type */
=>
strncpy(output, str, sizeof(output));
Note, you should check if 'output' is big enough to hold 'str'
The error in this case makes sense. output is a buffer that will hold come char data, while str is a pointer to some other area in memory. You don't want to assign the address of what str is pointing to output, right? If you want to go with this approach I think would just copy the data pointed to by str into output. Better yet just use str if no conversion is required.
C does not allow arrays to be modified by direct assignment - you must individually modify the array members. Thus, if you want to copy the string pointed to by str into the array output, you must use:
strcpy(output, str);
or perhaps
memcpy(output, str, strlen + 1);
(In both cases, after first checking that strlen < sizeof output).
Note that naming a local variable strlen, thus shadowing the standard function of that name, is going to more than a little confusing for someone who looks at your code later. I'd pick another name.

C: Proper syntax for allocating memory using pointers to pointers

This is my first time posting here, hopefully I will not make a fool of myself.
I am trying to use a function to allocate memory to a pointer, copy text to the buffer, and then change a character. I keep getting a segfault and have tried looking up the answer, my syntax is probably wrong, I could use some enlightenment.
/* My objective is to pass a buffer to my Copy function, allocate room, and copy text to it. Then I want to modify the text and print it.*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int Copy(char **Buffer, char *Text);
int main()
{
char *Text = malloc(sizeof(char) * 100);
char *Buffer;
strncpy(Text, "1234567890\n", 100);
Copy(&Buffer, Text);
}
int Copy(char **Buffer, char *Text)
{
int count;
count = strlen(Text)+1;
*Buffer = malloc(sizeof(char) * count);
strncpy(*Buffer, Text, 5);
*Buffer[2] = 'A'; /* This results in a segfault. "*Buffer[1] = 'A';" results in no differece in the output. */
printf("%s\n", *Buffer);
}
Your problem is simply one of precedence. The [] operator has higher precendence that unary-*, so the line is parsed as if it was:
*(Buffer[2]) = 'A';
...which is not what you want. You actually want the * to happen first, so you need to use parantheses:
(*Buffer)[2] = 'A';
Additionally, your strncpy() call is wrong. strncpy() does not nul-terminate the result if the number of characters copied is equal to the length; and since your memory comes straight from malloc(), there may not be a nul-terminator there already. strncpy() is actually the wrong tool in 99.99% of the cases that you will encounter - search on this site for numerous other answers explaining why.
A call to strncat() can be used instead:
(*Buffer)[0] = '\0'; /* Truncate to an empty string */
strncat(*Buffer, Text, 5);
*Buffer[2] is getting interpreted as *(Buffer[2]). What you want is (*Buffer)[2].
The problem is that *Buffer[2] means *(Buffer[2]) - you're trying to dereference the wrong pointer. You want to use (*Buffer)[2].

Is there a function akin to fprintf but only returns the result of formated string in C?

fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
I don't want to output anything via fprintf,but only the result of "Error in pcap_findalldevs: %s\n", errbuf,what's the function for that?
snprintf allows you to format to a char buffer and performs bounds checking to ensure the buffer is not overrun.
The commonly used sprintf does not perform bounds checking, and as such is inherently unsafe.
int sprintf(char * ptr, const char * format, ...)
Writes the output and a terminating null to a buffer at ptr, returns the number of characters written excluding the null. Dangerous if you don't know how big your output should be, it will blindly write past the end of the buffer.
int snprintf(char * ptr, size_t n, const char * format, ...)
Same as sprintf, but will write a maximum of n characters, including the trailing null. Returns the number of characters that would be written if n was large enough, so that you can reallocate your buffer if necessary.
int asprintf(char ** ptr, const char * format, ...)
Same as sprintf except a double pointer is passed in, the buffer will be resized if necessary to fit the output. This is a GNU extension, also available in BSD, it can be emulated like (Ignoring error checking)
int asprintf(char ** ptr, const char * format, ...){
va_list vlist;
va_start(vlist,format);
int n = vsnprintf(NULL,0,format,vlist);
*ptr = realloc(*ptr,n+1);
n = vsnprintf(*ptr,n+1,format,vlist);
va_end(vlist);
return n;
}
That is sprintf() which also has some useful variations, like vsprintf() which takes a pointer to an argument list. There are also buffer protection versions in some implementations.
sprintf copies the result to a char * instead of writing it to stdout or a file.
Syntax differences
printf(const char format, ...)
fprintf(FILE * file, const char format, ...)
sprintf(char * string, const char format, ...)
sprintf is the original call, but should be considered deprecated in favor of snprintf which allows you to pass a size. Another alternative is asprintf, which will allocate a string large enough to hold the result.

Resources