questions about a particular string within printf - c

I found this C language fragment:
printf("[%d] %.*s\n", cnt++, temp - field, field);
where temp and field are char * and cnt is an integer.
But I don't understand the use of %.*s in format string within printf.
Can-please-any of you help me ?

You can use .* in printf to specify that the precision is to be given as an argument. In your case, that argument is temp - field, the difference between the two pointers.

From some documentation:
.*: The precision is not specified in the format string, but as an additional integer value argument preceding the argument that has to be formatted.
So, in your case, field has the value and temp-field its precision.
These percentage-sign symbols, for future reference are called format specifiers. (In fact I found the answer to this question by googling just that.)

There are two parts for this answer,
That line is doing pointer arithmetic, a way to calculate the length of a string; based on a convention used in your application perhaps.
char *string = "abcdef";
char *p1 = string + 3; // def
char *p2 = string + 4; // ef
printf("%s - %s = %d\n", p1, p2, (int) (p1 - p2));
output
0x400709 - 0x40070a = -1
Note that p2 is a shorter string, but a bigger pointer.
.number is used to specify the precision of integers or the length of a string.
// number precision
printf("%.2f\n", 100.12345); // 100.12
char *string = "abcdef";
// print the first 3 characters only
printf("%.3s\n", string); // abc
// print the first X characters
int dynamicLength = 2;
printf("%.*s\n", dynamicLength, string); // ab
Note that by using .* what you are saying is:
I won't know the precision until the program is running.

Related

What does the 2nd argument in strtoul() function do?

According to this document,
The second argument (char **endptr) seems to be a waste of space! If
it is set to NULL, STRTOL seems to work its way down the string until
it finds an invalid character and then stops. All valid chars read are
then converted if the string starts with an invalid character the
function returns ZERO (0).
It means that the following code should detect 2 as the hex number:
int main()
{
char * string = "p1pp2ppp";
unsigned integer = strtoul(string, NULL, 16);
printf("%u", integer);
return 0;
}
but, it is returning zero.
Why?
The man page says the following about the second argument:
If endptr is not NULL, strtol() stores the address of the first
invalid character in *endptr. If there were no digits at all,
strtol() stores the original value of nptr in *endptr (and
returns 0). In particular, if *nptr is not '\0' but **endptr is
'\0' on return, the entire string is valid.
For example:
char str[] = "123xyz45";
char *p;
long x = strtol(str, &p, 10);
printf("x=%ld\n", x);
printf("p - str = %d\n", p - str);
printf("*p = %c\n", *p);
printf("p (as string) = %s\n", p);
Output:
x=123
p - str = 3
*p = x
p (as string) = xyz45
We can see that when strtol returns p points to the first character in str that cannot be converted. This can be used to parse through the string a bit at a time, or to see if the entire string can be converted or if there are some extra characters.
In the case of your example, the first character in string, namely "p" is not a base 10 digit so nothing gets converted and the function returns 0.
Why?
It's returning 0 because "p..." does not follow any rules about integer representation. The 2nd argument is not relevant for your question.
The char **endptr argument in all the strto* functions is intended to receive the address of the first character that isn’t part of a valid integer (decimal, hex, or octal) or floating point number. Far from useless, it’s handy for checking invalid input. For example, if I meant to type in 1234 but fat-fingered something like 12w4, strtoul will return 12 and set the endptr argument to point to w.
Basically, if the character endptr points to isn’t whitespace or 0, then the input should most likely be rejected.

Printing specific character from a string in C

I'm working on prefixing of a string for example : com should give me c co com.
I know to print a character in this was printf("%.5s",string) to print the first five values. I want to do this in a loop instead of 5 how can I replace it with i which is a incrementing value,something like this printf("%.is",string). how can I obtain this?
In printf format specifiers, all field widths (before the dot) and precisions (after the dot) can be given as asterisk *. For each asterisk, there must be one additional int argument before the printed object.
So, for your problem:
printf("%.*s", i, string);
Note that the additional parameter must be an int, so if you have another integer type, you should cast it:
size_t len = strlen(len);
if (len > 2) printf("%.*s", (int) (len - 2), string);
This is the simplest way of achieving what you want.
printf("%.*s\n", i, string);
If you want to generate the format string, you can do it too
char format[100]; /* the size should be estimated by you */
snprintf(format, sizeof(format), "%%.%ds", i);
printf(format, string)
check the snprintf() return value to ensure that the string was not truncated, if you choos a reasonable size for the format string it will be unlikely, but you should check anyway.
Above, the format specifier means
A literal "%"
Then a "."
Then the integer "%d"
Then the letter "s"
so the resulting string will be the format string you need to pass to printf().
Try this:
char s[] = "com";
for(size_t i = 1; i <= strlen(s); i++)
{
for(int j = 0; j < i; j++)
printf("%c", s[j]);
printf(" ");
}

Saving a string as an integer in a struct. C

I am trying to read strings from a file and convert them to integers for storage in a struct. The strtol() function works well but removes any 0s from the start of the tokens. Is there any way I can keep them? The input file is formatted like the example below.
003345.755653
000046.003265
073532.003434
122280.065431
Input file ^^^
struct store{
int *age;
int *ref;
}rec[20];
char *token;
char*ptr;
while (!feof (filea)){
fgets(buffer, sizeof buffer, filea);
token = strtok(buffer, ".");
rec[count].age = malloc(10);
rec[count].age = strtol(token, &ptr, 10);
printf("Age: %i\n", rec[count].age);
token = strtok(NULL, ".");
rec[count].ref = malloc(10);
rec[count].ref = strtol(token, &ptr, 10);
printf("Ref: %i\n\n", rec[count].ref);
count++;
}
Once your string has been converted to an int or any other numeric type, all its leading zeros are gone, because they do not change the value of an integer.
You can add back leading zeros to get your numbers all have the same number of digits, but matching the exact number of leading zeros from a file would require additional storage.
Here is how you can format all your integers to two digits, with zero padding if necessary:
printf("Age: %02i\n", rec[count].age);
Note: Your program has multiple errors. You need to fix them before it starts working properly.
You declare age and ref as pointers, but you use them like scalar variables
You allocate memory to age and ref using malloc, and then you override it with a numeric value
You ignore the new value of ptr after the read. You should use it to see if anything has been read from the file.
The compiler must have issued multiple warnings related to the issues described above. It is a good idea to treat all compiler warnings as errors, because it helps you find simple problems like these.
No, you can't keep the zeros! The computer needs them - those are not growing on trees! No seriously: If you want to "keep" them long you'll just have to append the 0s in front of the printed of file-written strings.
You can use printf("%013.6f\n", a); where %0 means "append zeros" on a field of 13 units where 6 of them are after the decimal point.
#include <stdio.h>
int main()
{
float a = 3345.755653;
float b = 46.003265;
float c = 73532.003434;
float d = 122280.065431;
printf("%013.6f\n", a);
printf("%013.6f\n", b);
printf("%013.6f\n", c);
printf("%013.6f\n", d);
return 0;
}

Defining value of scanf string letters to be read with a variable value

With printf it is perfectly normal to do:
int dec = 3;
float n = 4.3232;
printf("%.*f", dec, n);
But in scanf() I want to replace 100
scanf(%100[^~], string)
with something like:
int a = 100;
scanf(%[***somtehing goes here***][^~], a, string);
But I didn't manage to do it.
Not sure if it is duplicate, I will delete the question if it is.
Edit: replaced '\n' with ~.
For your stated purpose it's probably better to do this:
fgets(string, a, stdin);
http://linux.die.net/man/3/fgets
Just do a first "pass" using sprintf() where you construct the format string that you then use with scanf():
char fmt[64];
const int a = 100;
sprintf(fmt, "%%%d[^\n]", a);
The first two % signs are parsed as a unit by sprintf(); they cause it to emit a single % into the destination string.
The second %d is just the regular code to format a (decimal) integer, it will emit 100.
So the result will be that fmt contains the string "%100[^\n]" (where the \n really means an embedded newline).
Then use fmt with scanf():
const int got = scanf(fmt, string);
As usual, be sure to check the value of got after the call, if it's not 1 then that means scanf() failed to do the requested conversion.

C Programming: Convert Hex Int to Char*

My question is how I would go about converting something like:
int i = 0x11111111;
to a character pointer? I tried using the itoa() function but it gave me a floating-point exception.
itoa is non-standard. Stay away.
One possibility is to use sprintf and the proper format specifier for hexa i.e. x and do:
char str[ BIG_ENOUGH + 1 ];
sprintf(str,"%x",value);
However, the problem with this computing the size of the value array. You have to do with some guesses and FAQ 12.21 is a good starting point.
The number of characters required to represent a number in any base b can be approximated by the following formula:
⌈logb(n + 1)⌉
Add a couple more to hold the 0x, if need be, and then your BIG_ENOUGH is ready.
char buffer[20];
Then:
sprintf(buffer, "%x", i);
Or:
itoa(i, buffer, 16);
Character pointer to buffer can be buffer itself (but it is const) or other variable:
char *p = buffer;
Using the sprintf() function to convert an integer to hexadecimal should accomplish your task.
Here is an example:
int i = 0x11111111;
char szHexPrintBuf[10];
int ret_code = 0;
ret_code = sprintf(szHexPrintBuf, "%x", i);
if(0 > ret_code)
{
something-bad-happend();
}
Using the sprintf() function like this -- sprintf(charBuffer, "%x", i);
-- I think will work very well.

Resources