Is there an easy way to concatenate string non-literals with literals? - c

I would like to be able to do this:
lcd_putc("\fDeposited $" & disp_money & "\nAdd $" & temp & " more");
Unfortunately, the string literals and non-literals don't concatenate that easily. I know how to concatenate two literals, and how to concatenate two non-literals (with strcat) but that's not really what I'm looking for. Can anyone help?

sprintf() and snprintf() are good for this.

strcat is the way to do it. For more advanced concatenation, consider sprintf:
sprintf (buf, "\fDeposited $%s\nAdd $%s more", disp_money, temp);

char *buf = (char*)calloc(1,512);
sprintf(buf, "\fDeposited $%0.2d\nAdd $%0.2d more", disp_money, temp);
?

I think you might be searching for sprintf
Example:
char string[50];
int file_number = 0;
sprintf( string, "file.%d", file_number );
file_number++;
output_file = fopen( string, "w" );

Memory management in C is manual. To concatenate the strings, you will need to provide an array variable with enough characters to hold the final result. You can allocate this buffer variable on the stack, as a local variable to your function, or on the heap, using malloc().
Or you can avoid allocating the buffer by avoiding performing concatenation, if what you intend to do is display the strings. In that case, the following:
lcd_putc("\fDeposited $");
lcd_putc(disp_money);
lcd_putc("\nAdd $");
lcd_putc(temp);
lcd_putc(" more");
is a simple way to write what you could use. This method has the disadvantage of incurring the overhead (if any) due to lcd_putc(). This method has the advantage of not require concatenation of strings.
If and when you do need to concatenate strings, you will want to use snprintf() to ensure that you do not overflow your buffer (see the name of this web site), so do not use sprintf().
Just to show you the way for that future day when you need to concatenate strings:
#define STR_DEPOSITED "\fDeposited $"
#define STR_ADD "\nAdd $"
#define STR_MORE " more"
int total_length = strlen(STR_DEPOSITED) + strlen(STR_ADD) + strlen(STR_MORE) + strlen(disp_money) + strlen(temp) + 1;
char * buffer = malloc(total_length + sizeof(char));
snprintf(buffer, "%s%s%s%s%s", STR_DEPOSITED, disp_money, STR_ADD, temp, STR_MORE);
You can also accomplish the same thing using strncpy(), strncat(). As a side note, also consider using strnlen() on the variables, in order not to read beyond the end of non-terminated buffer.

Strings are not first class objects in C, so there is no language support for concatenation in the way you describe. There are, however, a lot of different functions that you can call that give you the output you need.
Probably the easiest to work with is sprintf. Be aware that you must supply an output buffer large enough to hold the resultant string, and sprintf doesn't do any bounds checking, if you have access to snprintf or sprintf_s then use that instead.
char output[SUFFICIENTLY_LARGE_VALUE];
sprintf (output, "\fDeposited $%s\nAdd $%s more", disp_money, temp);
%s in the sprintf string represents a place where a string parameter will be inserted, the first % is the first argument (disp_money) and the second % is the second argument (temp).

Related

strncpy and strcat usage

My homework requires that my name be displayed such that it looks like this: 'Lastname, Firstname'. Last name then [comma space] firstname. While not moving over the rest of the text after that name. This is my code:
char str1[11];
char str2[3];
char str3[16];
strcpy (str1,fn);
strcpy (str2,", ");
strcpy (str3,ln);
strncat (str1, str2, 14);
strncat (str1, str3, 31);
My teacher said that I did what he wanted, but he doesn't like how many lines of code I used and said I am doing extra work than I need.
Variables: ln = last name, fn = first name I made str2 for the ', ' comma space.
What is it that he wants me to do?
Assuming you know length of strings, why not do
char result[50];
sprintf(result,"%s, %s",ln, fn);
char result[50];
strcpy(result, ln);
strcat(result, ", ");
strcat(result, fn);
He's right, you used way too many statements (and wasted too much memory doing it).
This is all you need:
strcpy (str1,ln); // Copy the last name to str1
strcat (str1,", "); // Now append ", " to the last name in str1
strcat (str1,fn); // Lastly, append the first name to str1
You must make sure that str1 is large enough to hold all of that. An array of 13 characters may not be sufficient.
Your strcpy calls are really unnecessary since you already have first name and last name in variables. You can just create a buffer big enough to hold the entire string then use strcat to create the final "lastname, firstname" string.
I'm surprised your instructor accepted your answer. You are accumulating your result in the char array str1, which you've declared has only 11 characters. Unless strlen(ln)+strlen(fn)<=8, you will overflow the space you've allocated for the result str1. In the bad old days, a C programmer would have simply allocated a result array that seemed big enough, and not bothered to check. The standard C library function sprintf in stdio.h is designed for this job:
#include <stdio.h>
...fn, ln defined...
char result[80]; /* 80 characters is probably enough */
sprintf(result, "%s, %s", ln, fn);
A modern C programmer would never assume that ln and fn were short enough not to overflow a result array, no matter how long. The safe, modern alternative would be to replace the sprintf call by snprintf:
snprintf(result, 80, "%s, %s", ln, fn);
You can also use the strcpy/strcat family of functions, which are in string.h. (Was this specified in your assignment?) The safe, modern equivalents are strncpy and strncat, which let you specify a maximum number of characters to copy. A quick and dirty but safe solution using these functions would be:
char result[80];
result[0] = '\0'; /* initialize result to "" */
strncat(result, ln, 40);
strcat(result, ", ") /* you know this adds exactly two characters */
strncat(result, fn, 38);
The strncpy call is dangerous because it may not leave a null-terminated string in result, which will cause a subsequent strcat to fail. This isn't many fewer lines than what you did, but using just these string.h functions, it's tough to do much better and be guaranteed you can't overflow the result buffer no matter what ln and fn are given.

Correct way of initializing a non known value String in C

Say I want to create a String that will hold some values based on another string. Basically, I want to be able to compress one string, like this: aaabb -> a3b2 - But my question is:
In Java you could do something like this:
String mystr = "";
String original = "aaabb";
char last = original.charAt(0);
for (int i = 1; i < original.length(); i++) {
// Some code not relevant
mystr += last + "" + count; // Here is my doubt.
}
As you can see, we have initialized an empty string and we can modify it (mystr += last + "" + count;). How can you do that in C?
Unfortunately, in C you cannot have it as easy as in Java: string memory needs dynamic allocation.
There are three common choices here:
Allocate as much as you could possibly need, then trim to size once you are done - This is very common, but it is also risky due to a possibility of buffer overrun when you miscalculate the max
Run your algorithm twice - the first time counting the length, and the second time filling in the data - This may be the most efficient one if the timing is dominated by memory allocation: this approach requires you to allocate only once, and you allocate the precise amount of memory.
Allocate as you go - start with a short string, then use realloc when you need more memory.
I would recommend using the second approach. In your case, you would run through the source string once to compute the compressed length (in your case, that's 5 - four characters for the payload "a3b2", and one for the null terminator. With this information in hand, you allocate five bytes, then use the allocated buffer for the output, which is guaranteed to fit.
In C (not C++) you can do something like this:
char mystr[1024];
char * str = "abcdef";
char c = str[1]; // will get 'b'
int int_num = 100;
sprintf(mystr, "%s%c%d", str, c, int_num);
This will create a string in 'mystr':
"abcdefb100"
You can then concatenate more data to this string using strcat()
strcat(mystr, "xyz"); // now it is "abcdefb100xyz"
Please note that mystr has been declared to be 1024 bytes long and this is all the space you can use in it. If you know how long your string will be you can use malloc() in C to allocate the space and then use it.
C++ has much more robust ways of dealing with strings, if you want to use it.
You can use string concatenation method strcat:
http://www.cplusplus.com/reference/cstring/strcat/
You define your string as following:
char mystr[1024]; // Assuming the maximum string you will need is 1024 including the terminating zero
To convert the character last into a string to be able to concatenate it, you use the following syntax:
char lastString[2];
lastString[0] = last; // Set the current character from the for loop
lastString[1] = '\0'; // Set the null terminator
To convert the count into a string you need to use itoa function as following:
char countString[32];
itoa (count, countString, 10); // Convert count to decimal ascii string
Then you can use strcat as following:
strcat(mystr, lastString);
strcat(mystr, countString);
Another solution is to use STL String class or MFC CString if you are using Visual C++.

String format works in fprintf but doesn't work in sprintf, gives segmentation fault

fprintf(fp,"IP: %d: %.*s\n",
ip,
strstr(strstr(p->data, "User-Agent:"),"\n") - strstr(p->data, "User-Agent:"),
strstr(p->data, "User-Agent: ") );
fclose(fp);
Hi All, as you can see, in the above statement, I am trying to write off just the User Agent header from a char pointer which contains the entire http packet data. The thing is, After fiddling with the string format, I came up with this %.*s format which lets me, dynamically select the number of characters to be printed to the file, and then prints them. What the code is basically doing is, first, it's printing an int, then the number of chars from the occurrence of "User-Agent:" to the very next occurrence new line character is passed, and that amount of chars are then passes starting at where the "User-Agent:" starts, from the entire packet data string. I know it's all pretty messy, but it's working fine. Except that it's not working in sprintf.
Please save all my hard word! Any help is appreciated!
char *stat;
sprintf(stat,"%.*s\0",
strstr(strstr(p->data, "User-Agent:"),"\n") - strstr(p->data, "User-Agent:"),
strstr(p->data, "User-Agent: ")) ;
You are not allocating memory for stat. Try
char *stat = malloc(MAXLEN);
snprintf(stat, MAXLEN, ...);
^ ^
When you use sprintf, you need an array of characters to write into. You're writing to an uninitialized pointer.
Try this instead:
char stat[200];
sprintf(stat, etc...
Well, you are trying to write the data into uninitialized unallocated random memory location. Now that can't possibly work.
Either do:
char stat[SUFFICIENTLY_LARGE_NUMBER];
snprintf(stat, SUFFICIENTLY_LARGE_NUMBER, ...);
or:
char *stat = malloc(SUFFICIENTLY_LARGE_NUMBER);
snprintf(stat, SUFFICIENTLY_LARGE_NUMBER, ...);
and make sure "SUFFICIENTLY_LARGE_NUMBER" is enough bytes that the string fits in and not unnecessarily huge.
PS: snprintf, because your format does not include length limits. If it does, sprintf is OK, but never ever use sprintf with unlimited %s. Your %.*s, while formally limited, is not enough, because the expression will happily return more than the size of the allocated buffer, so you need another check to avoid overruning it.

snprintf vs. strcpy (etc.) in C

For doing string concatenation, I've been doing basic strcpy, strncpy of char* buffers. Then I learned about the snprintf and friends.
Should I stick with my strcpy, strcpy + \0 termination? Or should I just use snprintf in the future?
For most purposes I doubt the difference between using strncpy and snprintf is measurable.
If there's any formatting involved I tend to stick to only snprintf rather than mixing in strncpy as well.
I find this helps code clarity, and means you can use the following idiom to keep track of where you are in the buffer (thus avoiding creating a Shlemiel the Painter algorithm):
char sBuffer[iBufferSize];
char* pCursor = sBuffer;
pCursor += snprintf(pCursor, sizeof(sBuffer) - (pCursor - sBuffer), "some stuff\n");
for(int i = 0; i < 10; i++)
{
pCursor += snprintf(pCursor, sizeof(sBuffer) - (pCursor - sBuffer), " iter %d\n", i);
}
pCursor += snprintf(pCursor, sizeof(sBuffer) - (pCursor - sBuffer), "into a string\n");
snprintf is more robust if you want to format your string. If you only want to concatenate, use strncpy (don't use strcpy) since it's more efficient.
As others did point out already: Do not use strncpy.
strncpy will not zero terminate in case of truncation.
strncpy will zero-pad the whole buffer if string is shorter than buffer. If buffer is large, this may be a performance drain.
snprintf will (on POSIX platforms) zero-terminate. On Windows, there is only _snprintf, which will not zero-terminate, so take that into account.
Note: when using snprintf, use this form:
snprintf(buffer, sizeof(buffer), "%s", string);
instead of
snprintf(buffer, sizeof(buffer), string);
The latter is insecure and - if string depends on user input - can lead to stack smashes, etc.
sprintf has an extremely useful return value that allows for efficient appending.
Here's the idiom:
char buffer[HUGE] = {0};
char *end_of_string = &buffer[0];
end_of_string += sprintf( /* whatever */ );
end_of_string += sprintf( /* whatever */ );
end_of_string += sprintf( /* whatever */ );
You get the idea. This works because sprintf returns the number of characters it wrote to the buffer, so advancing your buffer by that many positions will leave you pointing to the '\0' at the end of what's been written so far. So when you hand the updated position to the next sprintf, it can start writing new characters right there.
Constrast with strcpy, whose return value is required to be useless. It hands you back the same argument you passed it. So appending with strcpy implies traversing the entire first string looking for the end of it. And then appending again with another strcpy call implies traversing the entire first string, followed by the 2nd string that now lives after it, looking for the '\0'. A third strcpy will re-traverse the strings that have already been written yet again. And so forth.
So for many small appends to a very large buffer, strcpy approches (O^n) where n is the number of appends. Which is terrible.
Plus, as others mentioned, they do different things. sprintf can be used to format numbers, pointer values, etc, into your buffer.
I think there is another difference between strncpy and snprintf.
Think about this:
const int N=1000000;
char arr[N];
strncpy(arr, "abce", N);
Usually, strncpy will set the rest of the destination buffer to '\0'. This will cost lots of CPU time. While when you call snprintf,
snprintf(a, N, "%s", "abce");
it will leave the buffer unchanged.
I don't know why strncpy will do that, but in this case, I will choose snprintf instead of strncpy.
All *printf functions check formatting and expand its corresponding argument, thus it is slower than a simple strcpy/strncpy, which only copy a given number of bytes from linear memory.
My rule of thumb is:
Use snprintf whenever formatting is needed.
Stick to strncpy/memcpy when only need to copy a block of linear memory.
You can use strcpy whenever you know exatcly the size of buffers you're copying. Don't use that if you don't have full control over the buffers size.
strcpy, strncpy, etc. only copies strings from one memory location to another. But, with snprint, you can do more stuff like formatting the string. Copying integers into buffer, etc.
It purely depends on your requirement which one to use. If as per your logic, strcpy & strncpy is already working for you, there is no need to jump to snprintf.
Also, remember to use strncpy for better safety as suggested by others.
The difference between strncpy and snprintf is that strncpy basically lays on you responsibility of terminating string with '\0'. It may terminate dst with '\0' but only if src is short enough.
Typical examples are:
strncpy(dst, src, n);
// if src is longer than n dst will not contain null
// terminated string at this point
dst[n - 1] = '\0';
snprintf(dst, n, "%s", src); // dst will 100% contain null terminated string

How to pass variable length width specifier in sscanf?

sscanf(input_str, "%5s", buf); //reads at max 5 characters from input_str to buf
But I need to use something like %MACRO_SIZEs instead of %5s
A trivial solution is to create a format string for the same
char fmt_str[100] = "";
snprintf(fmt_str, 100, "%%%ds", MACRO_SIZE);
sscanf(input_str, fmt_str, buf);
Is there a better way to achieve the same?
Like Stefan said, but for sscanf() to more properly answer the question, and with a bit more macro trickery:
#define MACRO_SIZE 5
#define FORMAT(S) "%" #S "s"
#define RESOLVE(S) FORMAT(S)
char buf[MACRO_SIZE + 1];
sscanf(input_str, RESOLVE(MACRO_SIZE), buf);
This uses C's automatic joining together of adjacent string literals, to form the required formatting string at compile-time. This only works if MACRO_SIZE is a preprocessor macro, not if it's a normal runtime variable.
The extra macro call through RESOLVE() is needed since otherwise the argument would not be resolved to its #defined value, and we'd end up with a formatting string of "%MACRO_SIZEs", which is not what we want.
if your MACRO_SIZE is const at compile time, you can try this:
#define MACRO_SIZE "5"
snprintf(fmt_str, 100, "%" MACRO_SIZE "s", buf);
The "correct" solution is what you call the trivial one. All these clever macros(I'd use m4 myself) are just going to make your code less manageable then if you just left it as a constant.
The problem you have here is strings are not a first class data structure in C. They are an array of bytes. Therefor you have to build the array you want to get the meaning you want, and you build that array with sprintf. It's not pretty, but it's correct.
If you're having performance issues and you've tracked it down to here then yes, eliminate the function calls. But unless the value for MACRO_SIZE is repeated a hundred times or spread out over multiple files I'd just change the literal. A macro is just faking having more flexibility, using sprintf actually gives you flexibility.

Resources