Reputation: 223
I'm using fgets to read a string in a char array, and then I want to move the pointer over 5 indices and copy the rest of the array into a separate array, BUT I don't want it to copy a newline character; so I've got something like this:
char str1[45], str2[50];
fgets(str2, 50, stdin);
*str2 += 5;
sprintf(str1, "%[^\n]s", str2);
but when I try to compile, I get an error that says:
unknown conversion type character â[â in format [-Wformat]
I'm pretty sure I've used the "%[^\n]s" before with scanf, and it worked just fine, any suggestions?
Upvotes: 0
Views: 2102
Reputation: 618
The pattern %[^n]s
is valid format for scanf
but it is not a valid format specifier for printf
(or sprintf
).
Additionally, *str2 += 5
does not skip the first 5 characters (as it appears to be the intention) but instead adds 5 for the byte stored in the first element of str2
. str2 = str2 + 5
will not compile since str2 is an array. You could assign the result to a temporary or pass it directly to sprintf.
Here is a slightly better way of doing what you are asking:
size_t len;
char *str1 = NULL, str2[50];
fgets(str2, 50, stdin);
len = strlen(str2);
if (len > 5) {
if (str2[len-1] == '\n') {
str2[len-1] = '\0'; // remove newline
len--;
}
str1 = str2 + 5;
len -= 5;
}
if (str1 != NULL) {
// do stuff
}
Upvotes: 1
Reputation: 545
Personally, I would just implement it from scratch with a simple for loop.
char str1[45], str2[50];
fgets(str2, 50, stdin);
size_t len = strlen(str2);
for (size_t k = 5; k < len; k += sizeof(char)) {
str1[k - 5] = str2[k];
}
Upvotes: 0
Reputation: 40145
#include <stdio.h>
int main(void){
char str1[45], str2[50];
if(fgets(str2, sizeof str2, stdin)){
int i=0, j;
for(j=0; str2[j] && str2[j] != '\n' && j < 5; ++j)
;
if(j == 5){//move success
while(str2[j] && str2[j] != '\n')
str1[i++] = str2[j++];
str1[i]=0;
puts(str1);
}
}
return 0;
}
Upvotes: 0
Reputation: 58568
To solve this problem properly, you must not lose sight of the fact that you're dealing with C arrays that have a limited size. The copy must not only stop at the newline, as required, but must ensure that the target array is properly null terminate, and that it is not overrun.
For this, it may be best to write a function, like:
#include <string.h>
/* Copy src to dst, until the point that a character from the bag set
* is encountered in src.(That character is not included in the copy.
* Ensures that dst is null terminated, unless dstsize is zero.
* dstsize gives the size of the dst.
* Returns the number of characters required to perform a complete copy;
* if this exceeds dstsize, then the copy was truncated.
*/
size_t copyspan(char *dst, size_t dstsize, const char *src, const char *bag)
{
size_t ideal_length = strcspn(src, bag); /* how many chars to copy */
size_t limited_length = (ideal_length < dstsize) ? ideal_length : dstsize - 1;
if (dstsize > 0) {
memcpy(dst, src, limited_length);
dst[limited_length] = 0;
}
return ideal_length + 1;
}
With this function we can now do:
if (copyspan(str1, str2, "\n") > sizeof str1) {
/* oops, truncated: handle this somehow */
}
Of course, there is also the issue that fgets
may have truncated the original data already.
Dealing with just the trailing newline that is usually returned by fgets
(except in the case of an overflowing line or a file not terminated by a newline) is usually done like this:
{
char line[128];
/*...*/
if (fgets(line, sizeof line, file)) {
char *pnl = strchr(line, '\n'); /* obtain pointer to first newline */
if (pnl != 0) /* if found, overwrite it with null */
*pnl = 0;
}
/*...*/
}
If you are doing this kind of line reading in many places, it is better to make a wrapper than to repeat this logic, of course.
Upvotes: 0
Reputation: 153367
"%[^\n]s"
is ok for scanf()
, but not with printf()
. Note: certainly the "s"
is superfluous.
Various methods exist to trim the trailing \n
. Suggest
if (fgets(str2, 50, stdin) == NULL) HAnlde_EOForIOError();
size_t len = strlen(str2);
if (len > 0 && str2[len-1] == '\n') len--;
if (len < 5) Handle_ShortString();
memcpy(str1, str2 + 5, len-5+1);
Note that strings returned from fegts()
do not always end in '\n'
.
See trimming-fgets
Upvotes: 1