1

I am using sscanf in my project to copy strings from source buffer to target buffer. For example:

char* target;
target = (char*)malloc(100 * sizeof(char));
char* source = "Hello World";
sscanf(source, "%[^\t\n]", target); // trying to copy "Hello World" into target.
printf("%s\n", target);//this will print "Hello World".

But this way of coding style is not accepted. What my manager want me to do is something like:

sscanf(source, "%11[^\t\n]", target); // NOTE: I've written "%11". here, 11 == length of hello world.

That means, he want me to provide format specifiers as well. (%11 in this case).

But, the problem is that source can be of varying length and I don't know how to write the correct format specifier for every varying length string.

user1367292
  • 1,029
  • 2
  • 11
  • 13
  • have you considered strtok() instead? – AndersK Aug 23 '13 at 11:31
  • The control string is just a string. You can count the number of characters and then assemble an appropriate control string. – Neil Kirk Aug 23 '13 at 11:34
  • 3
    [Please don't cast the return value of `malloc()` in C](http://stackoverflow.com/a/605858/28169). Also, don't use `sizeof (char)`, it's always 1 and just adds confusion. – unwind Aug 23 '13 at 11:39
  • I don't know much about C. What difference does adding the size of the string make? – Neil Kirk Aug 23 '13 at 13:11
  • @Neil Kirk If I _grok_ your comment: adding "11" to form "%11[^\t\n]" limits the maximum number of `char` put in `target` as `source` could have been much bigger than the destination's capacity. – chux - Reinstate Monica Aug 23 '13 at 13:18
  • @chux Thanks. If I understand this problem correctly, what is the point of working out the size of the string and then using that limit again? – Neil Kirk Aug 23 '13 at 14:40
  • @Neil Kirk OP's nicely terse post prevented me from divining that detail as to why `source` size is used twice. `target = strdup(source)` looks good (expect it does not filter out \t\n. It would seem that target successfully allocated with size of strlen(source)+1 would allow `sscanf(source, "%[^\t\n]", target)` to _always_ work. Maybe OP's manger wants 2 safety nets? – chux - Reinstate Monica Aug 23 '13 at 14:55

4 Answers4

7

Use:

sscanf(source, "%*[^\t\n]", maxlen, target)

where maxlen is the size you want to read.

There appears to be no trivial way to make a format string for sscanf (or any of it's siblings) take an arbitrary max length of the input string. The suggestion was based on printf being orthogonal to scanf, which turns out to not be the case.

You may find you have better luck using strtok and either strncpy or strdup to copy the token.

However, since it's tagged C++, why not use:

std::stringstream ss(source);  
std::string target;
getline(ss, target, "\t");
Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • I have used this line ---> scanf(source, "%*[^\t\n]", maxlen, target); but its giving me garbage value. – user1367292 Aug 23 '13 at 12:10
  • 1
    Yeah, it's incorrect - `scanf()` isn't orthogonal to `printf` in this aspect. It means "skip input", not "take input value to be length". I don't actually think there is a C way [aside from using something like `sprintf` to generate a string from it]. I will edit my answer to that effect... – Mats Petersson Aug 23 '13 at 12:27
  • I think you mean "analogous" instead of "orthogonal" – pelletjl Aug 23 '13 at 12:41
  • @pelletjl: No, I'm using orthogonal in the computer science meaning: http://en.wikipedia.org/wiki/Orthogonality#Computer_science – Mats Petersson Aug 23 '13 at 12:47
0

For copying string use strcpy(). It does not allocate space, so you have to provide the second buffer too. There's also strncpy() which will not copy more than specified characters.

If you want to make a copy of a string in one go you can use strdup(), just don't forget to free the memory afterwards.

Caladan
  • 1,471
  • 11
  • 13
0

First, use strcpy() for this.

Second, the format specifier is just a string, so just use sprintf() to make it after taking strlen() of the string you want.

Crowman
  • 25,242
  • 5
  • 48
  • 56
0

Use target = strdup(source) or if still obliged to use sscanf():

Dynamically create the format.

const char* source = "Hello World";
size_t n = 10;  // See note below
char* target;
target = (char*) malloc(n);  // (char *) is needed for C++, but not C
char format[1+20+5+1];
sprintf(format, "%%" "%zu" "[^\t\n]", n - 1);
sscanf(source, format, target); // trying to copy "Hello World" into target.
printf("%s\n", source);//this will print "Hello World".
printf("%s\n", target);//this will print "Hello Wor".

You would likely want n = strlen(source) + 1, but the above illustrates how a dynamically created format specifier for scanf() prevents buffer overrun in target.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256