How do I remove 20 spaces from the beginning of a buffer and 20 at the end?
I can run a for loop starting at 20 and -20 at the end total but how do I copy each char by char to another buffer or is there a simple padding command?
Thanks for all the help so far now works but just displays a about 20 charactors i.e the MFI-40576-021 section from the dump it does now skip the 20 crap bytes at the start.
ReadFile(h,buffer,0x224,&read,NULL);
buffer[read] = '\0';
char newbuff[1000];
memcpy(newbuff,buffer+20,sizeof(buffer)-40);
Create a new buffer of size s-40, do a memcpy from the source+20 to the destination for size s.
int read; //assumed
char buffer[0x224];
ReadFile(h,buffer,0x224,&read,NULL);
if(read-40 <=0) return;
char *newvar = (char*)malloc(read - 40 + 1); // Fails with void to char error
strncpy(newvar, buffer+20, read - 40);
newvar[read-40] = '\0';
If altering the original buffer is acceptable, it may be easiest to use memmove:
char* string = /* insert code here to obtain the string */;
size_t len = strlen(string) - 40; // Number of bytes to move
memmove(string, string + 20, len); // Move string down by 20 bytes
memset(&string[len], 0, 40); // Clear out the remaining buffer
This general procedure will also work if the data in your buffer is not a string. You'll just need to replace the strlen call with whatever code is needed to obtain the original buffer's length.
Use strncpy:
char *string = // however you obtain the string
char *new = malloc(strlen(string) - 40 + 1);
strncpy(new, string + 20, strlen(string) - 40);
Related
I am trying to make this dynamic reallocation work in a portable fashion.
My program accepts a line of text from a user and appends it to a buffer. If the length of text in the buffer is 20 or more, it removes the first 20 characters and moves any characters after that to the start of the buffer.
I have this code which works clean on Linux but when I run it on windows it emits garbage. Does anyone know why/how to make this portable only using malloc. IE not using string.h(strcpy) str... anything but len.
c17 only - no broken stucts(not portable). here is my code. Compiles with no errors gcc 7.3, mingw 7.3. I replace gets and puts with safer functions and I still get garbage on windows. I assume this is a formatting issue...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
void wbuff (message)
char *message;
{
FILE *f = fopen("file.txt", "w");
fprintf(f, "%s", message);
fclose(f);
}
char *rean (message)
char *message;
{
/* performs (write) on buffer, trims lefover, then restores */
char buf[80] = "";
puts("enter a line");
gets(buf);
int bln = strlen( buf );
int mln = strlen( message );
int nln = bln + mln;
printf("new length %d\n", nln);
message = realloc(message, nln);
memmove(message + mln, buf, bln);
/* MISTAKE IS HERE?! */
if( nln >= 20 ) {
int exl = nln -20; // leftover length
char *lo = realloc(NULL, exl); // leftover placeholder
memmove(lo, message+20, exl); // copy leftover
wbuff(message); // write clear buff
message = realloc(NULL, nln);
message = realloc(NULL, exl); // resize buffer
memmove(message, lo, exl); // restore leftover
}
return message;
}
void main (void)
{
char *message = "";
message = realloc(NULL, 0);
while ( 1 == 1 ) {
message = rean( message );
puts(message);
}
return;
}
In C, strings are a sequence of characters terminated by a null byte. You have a number of off-by-one errors here mostly related to not accounting for that fact, as well as memory leaks.
When you first set message in main:
char *message = "";
message = realloc(NULL, 0);
message either is NULL to points to 0 bytes of memory. When you call then call rean the first time:
int mln = strlen( message );
You're either attempting to dereference a NULL pointer to read past the end of allocated memory. You want to allocate at least 1 byte to start and set that byte to 0 so you have an empty string:
char *message = realloc(NULL, 1);
message[0] = '\0';
Then later when you copy the buffer into the message:
message = realloc(message, nln);
memmove(message + mln, buf, bln);
You don't allocate enough space for the terminating null byte, nor do you copy it, so you don't really have a string. When you then try to print it, either puts or printf reads past the end of the allocated memory. You need to allocate 1 extra byte and copy 1 extra byte:
message = realloc(message, nln + 1); // allocate 1 extra byte for the null terminator
memmove(message + mln, buf, bln + 1); // copy 1 extra byte
There are similar issues when you recopy anything past 20 characters:
int exl = nln -20; // leftover length
char *lo = realloc(NULL, exl); // leftover placeholder
memmove(lo, message+20, exl); // copy leftover
wbuff(message); // write clear buff
message = realloc(NULL, nln);
message = realloc(NULL, exl); // resize buffer
memmove(message, lo, exl); // restore leftover
lines 2-3: You don't allocate space for the terminating null byte for lo nor do you copy it.
line 5: You leak the memory previously held by message in the first realloc by passing assigning to message while using NULL as the first argument
line 6-7: You leak the memory allocated in line 5 by doing the same thing. Also, you again don't allocate space for the null byte, nor do you copy it on the next line.
As before, allocate 1 extra byte for each allocation and move 1 extra byte to account for the null terminator. Also, free lo at the end of the block, remove the extra realloc for message, and pass the prior value of message to realloc so you don't leak memory:
int exl = nln -20;
char *lo = realloc(NULL, exl + 1); // allocate 1 extra byte
memmove(lo, message+20, exl + 1); // copy 1 extra byte
wbuff(message);
// remove extra realloc
message = realloc(message, exl + 1); // pass in old message, allocate 1 extra
memmove(message, lo, exl + 1); // copy 1 extra byte
free(lo); // free leftover
These issues of reading and writing past the end of allocated memory all invoke undefined behavior, which explains why you see different results on different operating systems.
As far as conforming code goes, use fgets intead of gets:
fgets(line, sizeof(line), stdin);
This function will include a newline in line if there's space for it, so be sure to remove it if that's the case.
Also change main to return int, and remove #include <malloc.h> since the malloc family of function is defined to reside in stdlib.h.
Had you used strcpy and strcat instead of memmove, you wouldn't have had to account for copying the null terminating byte as those functions do that for you. You would still however need to account for that when allocating memory. There's also no conflict between strcpy, malloc, and realloc, as they are all part of the standard and work together properly. Using them together is no problem. If they aren't working properly for you then you aren't using them correctly.
After applying my updates, you can replace this:
memmove(message + mln, buf, bln + 1);
With this:
strcat(message, buf);
And replace this:
memmove(lo, message+20, exl + 1); // copy leftover
...
memmove(message, lo, exl + 1); // restore leftover
With this:
strcpy(lo, message+20);
...
strcpy(message, lo);
And it will still work properly and be conforming.
In some network code I need to encode packet structures in a buffer to send(2) over a socket but memcpy'ing the encoded buffers into a bigger buffer seems problematic.
Here's a small code example illustrating what I am doing:
char tbuf[] = "test";
char *buf = malloc(300);
memset(buf, '\0', 300);
int bytes_to_copy = 300;
int bytes_copied = 0;
while (bytes_copied < bytes_to_copy) {
memcpy(buf + bytes_copied, tbuf, sizeof(tbuf));
bytes_copied += sizeof(tbuf);
}
/* free, return */
This should append "test" 60 times into buf but buf ends up only containing one "test". Am I using memcpy wrong?
You are repeatedly copying the null terminator at the end of test. sizeof tbuf is 5.
So all the C standard library functions will ignore all the other concatenants.
The solution: copy one less byte in the memcpy, and be sure to add a null terminator to the final string.
I have a function that will parse some data coming in. My problem is that after using strncpy I get some garbage when I try to print it. I try using malloc to make the char array the exact size.
Code:
void parse_data(char *unparsed_data)
{
char *temp_str;
char *pos;
char *pos2;
char *key;
char *data;
const char newline = '\n';
int timestamp = 0;
temp_str = (char*)malloc(strlen(unparsed_data));
g_print("\nThe original string is: \n%s\n",unparsed_data);
//Ignore the first two lines
pos = strchr(unparsed_data, newline);
strcpy(temp_str, pos+1);
pos = strchr(temp_str, newline);
strcpy(temp_str, pos+1);
//Split the line in two; The key name and the value
pos = strchr(temp_str, ':'); // ':' divides the name from the value
pos2 = strchr(temp_str, '\n'); //end of the line
key = (char*)malloc((size_t)(pos-temp_str)-1); //allocate enough memory
data = (char*)malloc((size_t)(pos2-pos)-1);
strncpy(key, temp_str, (size_t)(pos-temp_str));
strncpy(data, pos + 2, (size_t)(pos2-pos));
timestamp = atoi(data);
g_print("size of the variable \"key\" = %d or %d\n", (size_t)(pos-temp_str), strlen(key));
g_print("size of the variable \"data\" = %d or %d\n", (size_t)(pos2-pos), strlen(data));
g_print("The key name is %s\n",key);
g_print("The value is %s\n",data);
g_print("End of Parser\n");
}
Output:
The original string is:
NEW_DATAa_PACKET
Local Data Set 16-byte Universal Key
Time Stamp (microsec): 1319639501097446
Frame Number: 0
Version: 3
Angle (deg): 10.228428
size of the variable "key" = 21 or 22
size of the variable "data" = 18 or 21
The key name is Time Stamp (microsec)
The value is 1319639501097446
F32
End of Parser
Run it again:
The original string is:
NEW_DATAa_PACKET
Local Data Set 16-byte Universal Key
Time Stamp (microsec): 1319639501097446
Frame Number: 0
Version: 3
Angle (deg): 10.228428
size of the variable "key" = 21 or 25
size of the variable "data" = 18 or 18
The key name is Time Stamp (microsec)ipe
The value is 1319639501097446
F
End of Parser
Your results are because strncpy does not put a null character at the end of the string.
Your strncpy(data, pos + 2, (size_t)(pos2-pos)); doesn't add a terminating \0 character at the end of the string. Therefore when you try to print it later, printf() prints your whole data string and whatever is in the memory right after it, until it reaches zero - that's the garbate you're getting. You need to explicitly append zero at the end of your data. It's also needed for atoi().
Edit:
You need to allocate one more byte for your data, and write a terminating character there. data[len_of_data] = '\0'. Only after that it becomes a valid C string and you can use it for atoi() and printf().
You need to malloc() +1 byte for a string, so it can append the zero when you do strcpy(), but the strncpy will not append zero as well you need a extra byte for it.
One problem: What if there's no newline?
Undefined behaviour:
pos = strchr(temp_str, newline);
strcpy(temp_str, pos+1);
The source and destination of strcpy must not overlap.
You have to remember in allocating space for a string to add one byte for the terminating '\0' character. You have to be careful with strncpy, especially if you are used to using strcpy, strcat, or sprintf. Those three functions terminate the string with '\0'. strncpy copies a number of bytes that you specify, and makes no assumption of terminating the string.
You assume that responsibility by making sure you place a '\0' at the end of the character buffer to which you copied. That means you have to know the starting the position and the length of the copy and put a '\0' one byte past the sum of the starting position and length.
I chose to solve a sample problem slightly differently, but it still involves knowing the length of what I copied.
In this case, I use strncpy to take the first 9 characters from pcszTestStr1 and
copy them to szTestBuf. Then, I use strcpy -- which terminates the string with a zero --
to append the new part of the sentence.
#include <stdio.h>
#include <string.h>
int n;
int argv_2;
char szTestBuf[100] = {0};
char * pcszTestStr1 =
"This is a very long, long string to be used in a C example, OK?";
int main(int argc, char *argv[])
{
int rc = 0;
printf("The following sentence is too long.\n%s\n", pcszTestStr1);
strncpy(szTestBuf, pcszTestStr1, 9);
strcpy(szTestBuf + 9, " much shorter sentence.");
printf("%s\n", szTestBuf);
return rc;
}
Here's the output of running test.c compiled gcc -o test test.c.
cnorton#hiawatha:~/scratch$ ./test
The following sentence is too long.
This is a very long, long string to be used in a C example, OK?
This is a much shorter sentence.
cnorton#hiawatha:~/scratch$
As simple as that. I'm on C++ btw. I've read the cplusplus.com's cstdlib library functions, but I can't find a simple function for this.
I know the length of the char, I only need to erase last three characters from it. I can use C++ string, but this is for handling files, which uses char*, and I don't want to do conversions from string to C char.
If you don't need to copy the string somewhere else and can change it
/* make sure strlen(name) >= 3 */
namelen = strlen(name); /* possibly you've saved the length previously */
name[namelen - 3] = 0;
If you need to copy it (because it's a string literal or you want to keep the original around)
/* make sure strlen(name) >= 3 */
namelen = strlen(name); /* possibly you've saved the length previously */
strncpy(copy, name, namelen - 3);
/* add a final null terminator */
copy[namelen - 3] = 0;
I think some of your post was lost in translation.
To truncate a string in C, you can simply insert a terminating null character in the desired position. All of the standard functions will then treat the string as having the new length.
#include <stdio.h>
#include <string.h>
int main(void)
{
char string[] = "one one two three five eight thirteen twenty-one";
printf("%s\n", string);
string[strlen(string) - 3] = '\0';
printf("%s\n", string);
return 0;
}
If you know the length of the string you can use pointer arithmetic to get a string with the last three characters:
const char* mystring = "abc123";
const int len = 6;
const char* substring = mystring + len - 3;
Please note that substring points to the same memory as mystring and is only valid as long as mystring is valid and left unchanged. The reason that this works is that a c string doesn't have any special markers at the beginning, only the NULL termination at the end.
I interpreted your question as wanting the last three characters, getting rid of the start, as opposed to how David Heffernan read it, one of us is obviously wrong.
bool TakeOutLastThreeChars(char* src, int len) {
if (len < 3) return false;
memset(src + len - 3, 0, 3);
return true;
}
I assume mutating the string memory is safe since you did say erase the last three characters. I'm just overwriting the last three characters with "NULL" or 0.
It might help to understand how C char* "strings" work:
You start reading them from the char that the char* points to until you hit a \0 char (or simply 0).
So if I have
char* str = "theFile.nam";
then str+3 represents the string File.nam.
But you want to remove the last three characters, so you want something like:
char str2[9];
strncpy (str2,str,8); // now str2 contains "theFile.#" where # is some character you don't know about
str2[8]='\0'; // now str2 contains "theFile.\0" and is a proper char* string.
I was going through an open source codebase and I see the following:-
char *buf;
char *line;
#define BUFSIZE 5000
buf = malloc(BUFSIZE)
line = buf;
while(fgets(line, (unsigned)(buf + BUFSIZE -line), in) != NULL) {
// do stuff
// ....
}
Why is the second argument to fgets given as buf + BUFSIZE - line?
That gives the number of characters from line to end of buf. Your //do stuff likely increments line
buf + BUFSIZE is a char * pointing to the first char after the memory allocated for buf
buf + BUFSIZE - line is an integral, the number of chars from line to buf + BUFSIZE - and therefore the number of characters you can safely write to line without overflowing buf
buf + BUFSIZE - line gives the free space in the buffer.
This way line can be a scrolling pointer pointing to the first free byte, where the next read operation can put the data.
Line will probably get incremented during the loop. Thus this expression shrinks the value of BUFSIZE by the size of text already read.
It's a guess, sicne you didn't post the loop.