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.
Related
I know strncpy is a safer version of strcpy as said here.
However, when I want to copy from src to dst and dst is not a clean buffer, I get unwanted results, which can be avoided by strcpy:
char *p = "123";
char a[10] = "aaaaaa";
strncpy(a,p,strlen(p));
printf("%s\n", a); // 123aaa
strcpy(a,p);
printf("%s\n", a); // 123 <- desired output, as the trailing a's are garbage
In my actual case, I know strlen(src) < sizeof(dst) (at least, if that isn't the case, the program will crash a lot sooner), so I can safely strcpy.
However, if strncpy is what I should use, then must I add after dst[strlen(src)] = '\0' to avoid garbage (or maybe better yet, init the buffer beforehand?)?
The third argument of strncpy is meant to represent the size of the target buffer. And when it fills it up, it doesn't add a null terminating character by design.
If you have sufficient space for the terminator and you insist on strncpy, just pass strlen(p) + 1 so it will not assume it exhausted the target buffer.
Like many already noted by now. This use of strncpy defeats the purpose, and is really no better than than a simple call to strcpy. The only practical use for strncpy, is if you want to overwrite a part of the string in-place (which is the use case you stumbled upon). Though that too is questionable use...
how to use strncpy correctly?
When code needs to copy a string to a destination and tolerates the result being not null character terminated nor fully copied, use the sizeof destination for the size argument:
char a[10];
// strncpy(a,p,strlen(p));
strncpy(a, p, sizeof a);
// printf("%s\n", a);
printf("%.*s\n", (int) sizeof a, a);
When code wants to copy a string and detect insufficient memory problems via strncpy() or needs null character '\0' padding, also use the sizeof destination.
char a[10];
strncpy(a, p, sizeof a);
if (a[sizeof a - 1] != '\0') {
// insufficient memory
// Maybe set last last character to the null character
a[sizeof a - 1] == '\0';
// or other more robust handling
return ERROR_INSUFFICIENT_MEMORY;
}
Otherwise do not use strncpy()
There are more efficient ways to detect insufficient memory than via strncpy() when null character '\0' padding is not needed. strncpy() zero fills the rest, if any, of the un-copied buffer. The below consumes much time zero-filling just to provide a insufficiency check.
char a[1000];
strncpy(a, "abc", sizeof a);
if (a[sizeof a - 1] != '\0') {
....
Better alternatives employ strlen(), strlcpy(), memcpy(). #Deduplicator.
See also strncpy or strlcpy in my case.
For a standard C lib one-liner, code could use snprintf() and a line of error detection. A good compiler would be expected to analyse snprintf(a, sizeof a, "%s", p) and emit efficient code.
// Copy with no overflow.
// 'a' is always null character terminated.
int len = snprintf(a, sizeof a, "%s", p);
if (len < 0 || (unsigned) len >= sizeof a) Report_truncated_copy();
strncpy() isn't actually a string-function; instead, it deals with which zero-padded sequences of non-zero characters, which together have a known fixed length. It's for example the right tool to fill in data-structures which are thereafter sent to other programs, to the outside, or persisted, to avoid data-leaks.
Trying to use it outside its very specialized niche leads to hideous contortions, and inefficient code.
There are more appropriate ways to go about it, like strlcpy() and/or manually using strlen() and memcpy().
char copy, array[20]
printf("enter ..."):
scanf("%s", array);
if (strlen(array) > 20 )
{
strcpy(copy, array....);
what would I need to do to make it only grab the first 20 character if the input is more then 20 character long
char array[20+1];
scanf("%20s", array);
Problem solved.
Your question is not clear, since the code makes little or no sense. Your input cannot be longer than 20 characters since the receiving array is only 20 characters. If the user inputs more, your program will produce undefined behavior. So, the main problem here is not limiting the copy, but rather limiting the input.
However, your question seems to be about limited-length string copying. If that's what you need, then unfortunately there no dedicated function in standard library for that purpose. Many implementation provide the non-standard strlcpy function that does exactly that. So, either check if your implementation provides strlcpy or implement your own strlcpy yourself.
In many cases you might see advices to use strncpy in such cases. While it is possible to beat strncpy into working for this purpose, in reality strncpy is not intended to be used that way. Using strncpy as a limited-length string copying function is always an error. Avoid it.
Use strncpy instead of strcpy. That's all there is to it. (Caution: strncpy does not nul-terminate the destination string if it hits its limit.)
EDIT: I didn't read your program carefully enough. You lose already at the scanf call if user input is longer than 20 characters. You should be calling fgets instead. (Personally I think *scanf should never be used - this is only the tip of the iceberg as far as problems they cause.) Furthermore, copy has room for only one character, not twenty; but I'm going to assume that's a typo on your part.
Alternatively, you don't need to use strcpy to read just 20 characters (and you won't have to include strings.h):
char c;
for( i = 0; i < 20; i++ ) {
c = getchar();
if (c != '\n') array[i] = c;
else break;
}
array[i+1] = '\0';
Don't forget to declare array as char array[21] to make sure '\0' will be included.
strncpy (copy, array, 20);
does the trick. Exxcept the string would NOT be null-terminated if it was >20 chars!
http://www.cplusplus.com/reference/clibrary/cstring/strncpy/
Use strncpy. Make sure to null terminate the destination.
You need to change your scanf() call, not your strcpy() call:
char copy[20], array[20];
printf("enter....");
scanf(%20s",array); // read a maximum of 20 characters
strcpy(copy, array);
I have this snippet of the code:
char* receiveInput(){
char *s;
scanf("%s",s);
return s;
}
int main()
{
char *str = receiveInput();
int length = strlen(str);
printf("Your string is %s, length is %d\n", str, length);
return 0;
}
I receive this output:
Your string is hellàÿ", length is 11
my input was:
helloworld!
can somebody explain why, and why this style of the coding is bad, thanks in advance
Several questions have addressed what you've done wrong and how to fix it, but you also said (emphasis mine):
can somebody explain why, and why this style of the coding is bad
I think scanf is a terrible way to read input. It's inconsistent with printf, makes it easy to forget to check for errors, makes it hard to recover from errors, and is incompatable with ordinary (and easier to do correctly) read operations (like fgets and company).
First, note that the "%s" format will read only until it sees whitespace. Why whitespace? Why does "%s" print out an entire string, but reads in strings in such a limited capacity?
If you'd like to read in an entire line, as you may often be wont to do, scanf provides... with "%[^\n]". What? What is that? When did this become Perl?
But the real problem is that neither of those are safe. They both freely overflow with no bounds checking. Want bounds checking? Okay, you got it: "%10s" (and "%10[^\n]" is starting to look even worse). That will only read 9 characters, and add a terminating nul-character automatically. So that's good... for when our array size never needs to change.
What if we want to pass the size of our array as an argument to scanf? printf can do this:
char string[] = "Hello, world!";
printf("%.*s\n", sizeof string, string); // prints whole message;
printf("%.*s\n", 6, string); // prints just "Hello,"
Want to do the same thing with scanf? Here's how:
static char tmp[/*bit twiddling to get the log10 of SIZE_MAX plus a few*/];
// if we did the math right we shouldn't need to use snprintf
snprintf(tmp, sizeof tmp, "%%%us", bufsize);
scanf(tmp, buffer);
That's right - scanf doesn't support the "%.*s" variable precision printf does, so to do dynamic bounds checking with scanf we have to construct our own format string in a temporary buffer. This is all kinds of bad, and even though it's actually safe here it will look like a really bad idea to anyone just dropping in.
Meanwhile, let's look at another world. Let's look at the world of fgets. Here's how we read in a line of data with fgets:
fgets(buffer, bufsize, stdin);
Infinitely less headache, no wasted processor time converting an integer precision into a string that will only be reparsed by the library back into an integer, and all the relevant elements are sitting there on one line for us to see how they work together.
Granted, this may not read an entire line. It will only read an entire line if the line is shorter than bufsize - 1 characters. Here's how we can read an entire line:
char *readline(FILE *file)
{
size_t size = 80; // start off small
size_t curr = 0;
char *buffer = malloc(size);
while(fgets(buffer + curr, size - curr, file))
{
if(strchr(buffer + curr, '\n')) return buffer; // success
curr = size - 1;
size *= 2;
char *tmp = realloc(buffer, size);
if(tmp == NULL) /* handle error */;
buffer = tmp;
}
/* handle error */;
}
The curr variable is an optimization to prevent us from rechecking data we've already read, and is unnecessary (although useful as we read more data). We could even use the return value of strchr to strip off the ending "\n" character if you preferred.
Notice also that size_t size = 80; as a starting place is completely arbitrary. We could use 81, or 79, or 100, or add it as a user-supplied argument to the function. We could even add an int (*inc)(int) argument, and change size *= 2; to size = inc(size);, allowing the user to control how fast the array grows. These can be useful for efficiency, when reallocations get costly and boatloads of lines of data need to be read and processed.
We could write the same with scanf, but think of how many times we'd have to rewrite the format string. We could limit it to a constant increment, instead of the doubling (easily) implemented above, and never have to adjust the format string; we could give in and just store the number, do the math with as above, and use snprintf to convert it to a format string every time we reallocate so that scanf can convert it back to the same number; we could limit our growth and starting position in such a way that we can manually adjust the format string (say, just increment the digits), but this could get hairy after a while and may require recursion (!) to work cleanly.
Furthermore, it's hard to mix reading with scanf with reading with other functions. Why? Say you want to read an integer from a line, then read a string from the next line. You try this:
int i;
char buf[BUSIZE];
scanf("%i", &i);
fgets(buf, BUFSIZE, stdin);
That will read the "2" but then fgets will read an empty line because scanf didn't read the newline! Okay, take two:
...
scanf("%i\n", &i);
...
You think this eats up the newline, and it does - but it also eats up leading whitespace on the next line, because scanf can't tell the difference between newlines and other forms of whitespace. (Also, turns out you're writing a Python parser, and leading whitespace in lines is important.) To make this work, you have to call getchar or something to read in the newline and throw it away it:
...
scanf("%i", &i);
getchar();
...
Isn't that silly? What happens if you use scanf in a function, but don't call getchar because you don't know whether the next read is going to be scanf or something saner (or whether or not the next character is even going to be a newline)? Suddenly the best way to handle the situation seems to be to pick one or the other: do we use scanf exclusively and never have access to fgets-style full-control input, or do we use fgets exclusively and make it harder to perform complex parsing?
Actually, the answer is we don't. We use fgets (or non-scanf functions) exclusively, and when we need scanf-like functionality, we just call sscanf on the strings! We don't need to have scanf mucking up our filestreams unnecessarily! We can have all the precise control over our input we want and still get all the functionality of scanf formatting. And even if we couldn't, many scanf format options have near-direct corresponding functions in the standard library, like the infinitely more flexible strtol and strtod functions (and friends). Plus, i = strtoumax(str, NULL) for C99 sized integer types is a lot cleaner looking than scanf("%" SCNuMAX, &i);, and a lot safer (we can use that strtoumax line unchanged for smaller types and let the implicit conversion handle the extra bits, but with scanf we have to make a temporary uintmax_t to read into).
The moral of this story: avoid scanf. If you need the formatting it provides, and don't want to (or can't) do it (more efficiently) yourself, use fgets / sscanf.
scanf doesn't allocate memory for you.
You need to allocate memory for the variable passed to scanf.
You could do like this:
char* receiveInput(){
char *s = (char*) malloc( 100 );
scanf("%s",s);
return s;
}
But warning:
the function that calls receiveInput will take the ownership of the returned memory: you'll have to free(str) after you print it in main. (Giving the ownership away in this way is usually not considered a good practice).
An easy fix is getting the allocated memory as a parameter.
if the input string is longer than 99 (in my case) your program will suffer of buffer overflow (which is what it's already happening).
An easy fix is to pass to scanf the length of your buffer:
scanf("%99s",s);
A fixed code could be like this:
// s must be of at least 100 chars!!!
char* receiveInput( char *s ){
scanf("%99s",s);
return s;
}
int main()
{
char str[100];
receiveInput( str );
int length = strlen(str);
printf("Your string is %s, length is %d\n", str, length);
return 0;
}
You have to first allocate memory to your s object in your receiveInput() method. Such as:
s = (char *)calloc(50, sizeof(char));
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
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).