Equivalent of write in printf in the following code? - c

I wanted to ask what will be the equivalent of this write statement in printf statement?
write(STDOUT_FILENO, buf + start, end - start);
Where buf is a char*, start is int, end is int.
The line which is confusing me is buf + start?
Or how can i save this to a char array using strcpy and then printf that char array. But i don't know how to copy the output of above code to char array. I am unable to understand what the line buf+start is doing.
thanks

The expression buf + start uses pointer arithmetic and is equivalent to &buf[start], the pointer to the position start in buf. The code you show prints the slice from start to end (exclusivley) of your char buffer buf.
If your buffer doesn't contain zeros, you can rewrite that as:
printf("%.*s", (int) (end - start), buf + start);
The cast to (int) isn't strictly necessary in your case, but the * precision in printf requires an int and one often uses size_t for positions, so I've made that a habit.

To copy this data you need
char *mybuffer;
mybuffer = malloc(end - start + 1);
if (mybuffer != NULL)
{
memcpy(mybuffer, buf + start, end - start);
mybuffer[end - start] = '\0';
}
There you go, now mybuffer can be used in a printf like function, you need to remember to do free(mybuffer) at some point after you are done using mybuffer. Also you need to check end - start >= 0 and be aware that if there is a null byte embeded into the data, the string will be shorter than end - start for what printf and family care.

Related

How do I print a string between two pointers?

I'm building a rocket for Elon Musk and the memory usage is very important to me.
I have text and a pointer to it pText. It's chilling in the heap.
Sometimes I need to analyse the string, its words. I don't store substrings in heap, instead I store two pointers start/end for represeting a substring of the text. But sometimes I need to print those substrings for debugging purposes. How do I do that?
I know that for a string to be printed I need two things
a pointer to the begging
null terminator at the end
Any ideas?
// Text
char *pText = "We've sold the Earch!";
// Substring `sold`
char *pStart = &(pText + 6) // s
char *pEnd = &(pStart + 3) // d
// Print that substring
printf("sold: %s", ???);
If you only want to print the sub-string, then use a precision argument for printf:
printf("sold: %.*s", (int) (pEnd - pStart) + 1, pStart);
If you need to use the sub-string in other ways then the simplest is probably to create a temporary string, copy into it, and then print that instead.
Perhaps something like this:
// Get the length of the sub-string
size_t length = pEnd - pStart + 1;
// Create an array for the sub-string, +1 for the null-terminator
char temp[length + 1];
// Copy the sub-string
memcpy(temp, pStart, length);
// Terminate it
temp[length] = '\0';
If you need to do this many times I recommend you create a generic function for this.
You might also need to dynamically allocate the string using malloc depending on use-case.

Working with substrings

I have string char * buff and want to work on its susbtring (from buff + x till buff + y.
Do I have to copy this sting to other variable? Or is there any better way to reach it?
Right now I only want to write this substring to a file.
No, just do the write directly just as you wish:
fwrite(buff + x, y - x + 1, 1, my_file);
The above assumes a closed interval by the way, if you mean a half-open you need to remove the + 1. For instance, with const char *buff = "hello, world"; the above will write "world" if x = 7 and y = 12.
The write will be done from the "slice" of your buffer, since that's all you say to fwrite(). It has no idea that the data it receives is part of something larger, of course.
As pointer out in a comment, the above treats the slice as binary data which might be bad if it's really a string. In that case, to be able to use e.g. fprintf() with %s, you should use a dynamic format string (you need %.Ns where N is y - x + 1):
static int substring_print(const char *s, size_t start, size_t end)
{
char fmt[16];
snprintf(fmt, sizeof fmt, "%%.%us", end - start + 1);
fprintf(stdout, fmt, s + start);
}

C - start traversing from the middle of a string

Just double checking because I keep mixing up C and C++ or C# but say that I have a string that I was parsing using strcspn(). It returns the length of the string up until the first delimiter it finds. Using strncpy (is that C++ only or was that available in C also?) I copy the first part of the string somewhere else and have a variable store my position. Let's say strcspn returned 10 (so the delimiter is the 10th character)
Now, my code does some other stuff and eventually I want to keep traversing the string. Do I have to copy the second half of the string and then call strncspn() from the beginning. Can I just make a pointer and point it at the 11th character of my string and pass that to strncspn() (I guess something like char* pos = str[11])? Something else simpler I'm just missing?
You can get a pointer to a location in the middle of the string and you don't need to copy the second half of the string to do it.
char * offset = str + 10;
and
char * offset = &str[10];
mean the same thing and both do what you want.
You mean str[9] for the 10th char, or str[10] for the 11th, but yes you can do that.
Just be careful that you are not accessing beyond the length of the string and beyond the size of memory allocated.
It sounds like you are performing tokenization, I would suggest that you can directly use strtok instead, it would be cleaner, and it already handles both of what you want to do (strcspn+strncpy and continue parsing after the delimiter).
you can call strcspn again with (str + 11) as first argument. But make sure that length of str is greater than 11.
n = strcspn(str, pattern);
while ((n+1) < strlen(str))
{
n2 = strcspn((str+n), pattern);
n += n2;
}
Note : using char *pos = str[11] is wrong. You should use like char *pos = str + 11;

Performing lots of string concatenation in C?

I'm porting some code from Java to C, and so far things have gone well.
However, I have a particular function in Java that makes liberal use of StringBuilder, like this:
StringBuilder result = new StringBuilder();
// .. build string out of variable-length data
for (SolObject object : this) {
result.append(object.toString());
}
// .. some parts are conditional
if (freezeCount < 0) result.append("]");
else result.append(")");
I realize SO is not a code translation service, but I'm not asking for anyone to translate the above code.
I'm wondering how to efficiently perform this type of mass string concatenation in C. It's mostly small strings, but each is determined by a condition, so I can't combine them into a simple sprintf call.
How can I reliably do this type of string concatenation?
A rather "clever" way to conver a number of "objects" to string is:
char buffer[100];
char *str = buffer;
str += sprintf(str, "%06d", 123);
str += sprintf(str, "%s=%5.2f", "x", 1.234567);
This is fairly efficient, since sprintf returns the length of the string copied, so we can "move" str forward by the return value, and keep filling in.
Of course, if there are true Java Objects, then you'll need to figure out how to make a Java style ToString function into "%somethign" in C's printf family.
The performance problem with strcat() is that it has to scan the destination string to find the terminating \0' before it can start appending to it.
But remember that strcat() doesn't take strings as arguments, it takes pointers.
If you maintain a separate pointer that always points to the terminating '\0' of the string you're appending to, you can use that pointer as the first argument to strcat(), and it won't have to re-scan it every time. For that matter, you can use strcpy() rater than strcat().
Maintaining the value of this pointer and ensuring that there's enough room are left as an exercise.
NOTE: you can use strncat() to avoid overwriting the end of the destination array (though it will silently truncate your data). I don't recommend using strncpy() for this purpose. See my rant on the subject.
If your system supports them, the (non-standard) strcpy() and strlcat() functions can be useful for this kind of thing. They both return the total length of the string they tried to create. But their use makes your code less portable; on the other hand, there are open-source implementations that you can use anywhere.
Another solution is to call strlen() on the string you're appending. This isn't ideal, since it's then scanned twice, once by strcat() and once by strlen() -- but at least it avoids re-scanning the entire destination string.
The cause of poor performance when concatenating strings is the reallocation of memory. Joel Spolsky discusses this in his article Back to basics. He describes the naive method of concatenating strings:
Shlemiel gets a job as a street painter, painting the dotted lines down the middle of the road. On the first day he takes a can of paint out to the road and finishes 300 yards of the road. "That's pretty good!" says his boss, "you're a fast worker!" and pays him a kopeck.
The next day Shlemiel only gets 150 yards done. "Well, that's not nearly as good as yesterday, but you're still a fast worker. 150 yards is respectable," and pays him a kopeck.
The next day Shlemiel paints 30 yards of the road. "Only 30!" shouts his boss. "That's unacceptable! On the first day you did ten times that much work! What's going on?"
"I can't help it," says Shlemiel. "Every day I get farther and farther away from the paint can!"
If you can, you want to know how large your destination buffer needs to be before allocating it. The only realistic way to do this is to call strlen on all of the strings you want to concatenate. Then allocate the appropriate amount of memory and use a slightly modified version of strncpy that returns a pointer to the end of the destination buffer.
// Copies src to dest and returns a pointer to the next available
// character in the dest buffer.
// Ensures that a null terminator is at the end of dest. If
// src is larger than size then size - 1 bytes are copied
char* StringCopyEnd( char* dest, char* src, size_t size )
{
size_t pos = 0;
if ( size == 0 ) return dest;
while ( pos < size - 1 && *src )
{
*dest = *src;
++dest;
++src;
++pos;
}
*dest = '\0';
return dest;
}
Note how you have to set the size parameter to be the number of bytes left until the end of the destination buffer.
Here's a sample test function:
void testStringCopyEnd( char* str1, char* str2, size_t size )
{
// Create an oversized buffer and fill it with A's so that
// if a string is not null terminated it will be obvious.
char* dest = (char*) malloc( size + 10 );
memset( dest, 'A', size + 10 );
char* end = StringCopyEnd( dest, str1, size );
end = StringCopyEnd( end, str2, size - ( end - dest ) );
printf( "length: %d - '%s'\n", strlen( dest ), dest );
}
int main(int argc, _TCHAR* argv[])
{
// Test with a large enough buffer size to concatenate 'Hello World'.
// and then reduce the buffer size from there
for ( int i = 12; i > 0; --i )
{
testStringCopyEnd( "Hello", " World", i );
}
return 0;
}
Which produces:
length: 11 - 'Hello World'
length: 10 - 'Hello Worl'
length: 9 - 'Hello Wor'
length: 8 - 'Hello Wo'
length: 7 - 'Hello W'
length: 6 - 'Hello '
length: 5 - 'Hello'
length: 4 - 'Hell'
length: 3 - 'Hel'
length: 2 - 'He'
length: 1 - 'H'
length: 0 - ''
If operations like these are very frequent, you could implement them in your own buffer class. Example (error handling omitted for brevity ;-):
struct buff {
size_t used;
size_t size;
char *data;
} ;
struct buff * buff_new(size_t size)
{
struct buff *bp;
bp = malloc (sizeof *bp);
bp->data = malloc (size);
bp->size = size;
bp->used = 0;
return bp;
}
void buff_add_str(struct buff *bp, char *add)
{
size_t len;
len = strlen(add);
/* To be implemented: buff_resize() ... */
if (bp->used + len +1 >= bp->size) buff_resize(bp, bp->used+1+len);
memcpy(buff->data + buff->used, add, len+1);
buff->used += len;
return;
}
Given that the strings look so small, I'd be inclined just to use strcat and revisit if performance becomes an issue.
You could make your own method that remembers the string length so it doesn't need to iterate through the string to find the end (which is potentially the slow bit of strcat if you are doing lots of appends to long strings)

malloc double datatype with strlen

how do I allocate memory for strlen(esc) in a proper way? The temp and str are char datatypes.
double esc = t1.tv_sec+(t1.tv_usec/1000000.0);
strAll = malloc(strlen(temp) + strlen(str) + strlen(esc) + 1);
You cannot take strlen(esc). As I am sure the compiler has already told you, the argument to strlen() must be char *, you are passing it a double. Try first converting the double to array of char with snprintf().
You can find the length you need using snprintf. Passing '0' as the size will prevent is from writing any bytes, and it returns the number of bytes it would have needed.
size_t length = snprintf(0, 0, "%lf%s%lf", esc, temp, esc) + 1;
strAll = malloc(length);
snprintf(strAll, length, "%lf%s%lf", esc, temp, esc);
You'll need to convert esc to a string, probably with sprintf(). Then use the length from that in the malloc():
char buffer[32];
int n = snprintf(buffer, sizeof(buffer), "%.6f", esc);
if (n >= sizeof(buffer))
...handle overlong string problems (bail out)...
char *strAll = malloc(strlen(temp) + strlen(str) + n + 1);
if (strAll == 0)
...handle out of memory problem (bail out)...
sprintf(strAll, "%s%s%s", temp, str, buffer);
(I didn't check the length returned by sprintf() because 'it cannot go wrong'. You calculated the length of the component strings, and therefore, it will fill exactly the allocated space. If you do decide to check it, then preserve the length that is the argument to malloc() and test against that.)
Your code don't compile. strlen expects a string argument, that is a pointer to a sequence of char (like an array).
Perhaps you want something like
char buf[30];
double esc = somedoublefunction();
snprintf (buf, sizeof(buf), "%f", esc);
return strdup(buf);
of course you should care to later free the resulting pointer.
Try using one of the following if you're just trying to save all the data in one buffer:
sizeof(esc) or sizeof(double)
If you want to turn esc into a string. Otherwise, I would suggest using a fixed point format when converting to a string e.g. snprintf(buffer, 7, "%03.3f", esc);

Resources