I'm trying to implement a quick prototype program to prepare a message that I intend to use as a tcp socket communication protocol.
I'm new at this, and I can't quite understand why running the following prints (null). Am I failing at passing the pointer to the subroutine?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char *header = "testhd";
void pack_message(char *body, char *buffer)
{
size_t body_size, msg_size, buffer_size;
char hex_size[11];
body_size = strlen(body);
snprintf(hex_size, 11, "0x%x", body_size);
msg_size = 16 + body_size;
buffer_size = msg_size + 1;
if (!buffer){
buffer = malloc(buffer_size);
}else{
buffer = realloc(buffer, buffer_size);
}
memset(buffer, 0, buffer_size);
strcat(buffer, header);
strcat(buffer, hex_size);
strcat(buffer, body);
}
int main(){
char *buffer = NULL;
char *body = "testmsg";
pack_message(body, buffer);
printf("%s", buffer);
return 0;
}
Please note that char *buffer in main function and char *buffer in pack_message function are two different pointers which are pointing to the same NULL address.
So in Your case functiom pack_message is working with local pointer and that's the reason why running Your code prints null.
To make Your code work You could potentially take an approach where You pass an address of pointer itself as an argument to the pack_message function so main function could look like that:
int main(){
char *buffer = NULL;
char *body = "testmsg";
pack_message(body, &buffer);
printf("%s", buffer);
return 0;
}
Your pack_message function should be changed to:
void pack_message(char *body, char **buffer)
{
size_t body_size, msg_size, buffer_size;
char hex_size[11];
body_size = strlen(body);
snprintf(hex_size, 11, "0x%zx", body_size);
msg_size = 16 + body_size;
buffer_size = msg_size + 1;
if (NULL == *buffer){
*buffer = malloc(buffer_size);
}else{
*buffer = realloc(*buffer, buffer_size);
}
memset(*buffer, 0, buffer_size);
strcat(*buffer, header);
strcat(*buffer, hex_size);
strcat(*buffer, body);
}
Please note that there I changed also one more potential issue:
snprintf(hex_size, 11, "0x%zx", body_size);
As body_size is of type size_t it is better idea to use %zx as size_t can be different size than unsigned integer, for details on printf please take a look at: https://cplusplus.com/reference/cstdio/printf/
Similar approach can be taken to char *body = "testmsg"; especially when its value will be much longer string.
For further improvements I would recommend to redesign pack_message function to return a pointer to allocated buffer as it will lower the chances to forget about freeing memory when not needed anymore.
Related
I have read a lot of the answers on the theoretical issues with memory allocation to pointer to arrays, but have not been able to fix my code...so turning to you.
I have an array of strings in a STRUCT, which I need to write to and read from. Declared as:
typedef struct client_mod
{
/* Client ad_file */
char *ad_filenames[10];
/* Client's current ad array index*/
unsigned int ad_index;
} client;
Then , inside a function , I assign values to pointer:
static int get_spots (client_mod *client)
{
char buf[512];
FILE *ptr;
if ((ptr = popen("php /media/cdn/getspot.php", "r")) != NULL) {
/* Read one byte at a time, up to BUFSIZ - 1 bytes, the last byte will be used for null termination. */
size_t byte_count = fread(buf, 1, 512 - 1, ptr);
/* Apply null termination so that the read bytes can be treated as a string. */
buf[byte_count] = 0;
}
(void) pclose(ptr);
// parse extracted string here...
int i = 0;
client->ad_filenames[i] = strdup(strtok(buf,"|"));
while(client->ad_filenames[i]!= NULL && i<5)
{
client->ad_filenames[++i] = strdup(strtok(NULL,"|"));
if (client->ad_filenames[i] != NULL && strlen(client->ad_filenames[i]) > 5) {
LOG("TESTING FOR CORRECT FILE NAMES %s\n", client->ad_filenames[i]);
}
}
}
The problem comes when I retreive the values later:
/* in looping code block */
LOG("Checking file under index = %d, file is %s", client->ad_index, client->ad_filenames[client->ad_index]);
The first two members of the array are retreived normally, everything after that is garbled.
I would appreciate any guidance. Thanks!
I understand this probablby comes from undefined behaviour of assigning directly to the pointer, but I can't figure out how to solve it.
I think the problem is with assigning to this struct element.
char *ad_filenames[10];
ad_filenames is an array of 10 of pointer to characters.
What that means is that memory allocation is needed for each index.
Something like
client->ad_filenames[0] = strdup(var1);
strdup() does both malloc() and strcpy() within this function.
client should be a variable name. You already defined client as a type.
Here is working code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct client_mod
{
/* Client ad_file */
char *ad_filenames[10];
/* Client's current ad array index*/
unsigned int ad_index;
}CLIENT1;
CLIENT1 *client;
int func( char *var1 ) {
client->ad_filenames[0] = strdup(var1);
}
int
main(void)
{
char str1[10];
client = malloc( sizeof client );
strcpy( str1, "Hello" );
func( str1 );
printf("%s\n", client->ad_filenames[0] );
free(client->ad_filenames[0]);
free (client);
}
Your problem is with the line,
size_t byte_count = fread(buf, 1, 1000 - 1, ptr);
Read the man fread page,
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
you read 1000-1 members of size 1 into buf, which is only allocated buf[512], either expand buf or decrease fread 3rd argument,
buf[1000+1];
size_t byte_count = fread(buf, 1, sizeof(buf)-1, ptr);
I`m trying to convert UTF-16LE to UTF-8 with iconv() in Linux.
and i think it done..
But i got some trouble.. with my code..
and i think two codes are same, but first one not working. only second one working.
#include "stdio.h"
#include "string.h"
#include "iconv.h"
#include "errno.h"
#if 1
int fn2Utf8(char inBuf[], char outBuf[]) {
size_t readBytes = sizeof(inBuf);
size_t writeBytes = sizeof(outBuf);
char* in = inBuf;
char* out = outBuf;
iconv_t convert = iconv_open("UTF-8","UTF-16LE");
if (iconv(convert, &in, &readBytes, &out, &writeBytes) < 0) {
return (-1);
}
iconv_close(convert);
printf("[%s] [%s]\n", inBuf, outBuf);
return (out - outBuf);
}
int main() {
char inBuf[128] ="\x5c\x00\xbd\xac\x01\xc6\x00\xd3\x5c\x00\x00\xb3\x78\xc6\x44\xbe\x5c\x00\x2a\x00\x00\x00";
char outBuf[128];
fn2Utf8(inBuf, outBuf);
return 0;
}
#else
int main() {
char inBuf[128] = "\x5c\x00\xbd\xac\x01\xc6\x00\xd3\x5c\x00\x00\xb3\x78\xc6\x44\xbe\x5c\x00\x2a\x00\x00\x00";
char outBuf[128];
size_t readBytes = sizeof(inBuf);
size_t writeBytes = sizeof(outBuf);
char* in = inBuf;
char* out = outBuf;
iconv_t convert = iconv_open("UTF-8","UTF-16LE");
if (iconv(convert, &in, &readBytes, &out, &writeBytes) < 0) {
return (-1);
}
iconv_close(convert);
printf("[%s] [%s]\n", inBuf, outBuf);
return 0;
}
#endif
You can complie two type of code with if 0 -> if 1
and i need if 1 method.
Here's the problem:
size_t readBytes = sizeof(inBuf);
size_t writeBytes = sizeof(outBuf);
When you pass arrays to a function, they decay to pointers to their first element. Your call
fn2Utf8(inBuf, outBuf);
is equal to
fn2Utf8(&inBuf[0], &outBuf[0]);
That means that in the function the arguments are not arrays, but pointers. And when you do sizeof on a pointer you get the size of the pointer and not what it's pointing to.
There are two solutions: The first is to pass in the length of the arrays as arguments to the function, and use that. The second, at least for the inBuf argument, is to rely on the fact that it's a null-terminated string and use strlen instead.
The second way, with strlen, works only on inBuf as I already said, but doesn't work on outBuf where you have to use the first way and pass in the size as an argument.
If works in the program without the function because then you are doing sizeof on the array, and not a pointer. When you have an array and not a pointer, sizeof will give you the size in bytes of the array.
I'm trying to write a function that prefixes a string with its length. I can't seem to assign a char[] to a char *. Mysteriously, if I print out some debugging code before the assignment, it works.
char *prefixMsgWLength(char *msg){
char *msgWLength;
int msgLength = strlen(msg);
if (msgLength == 0){
msgWLength = "2|";
}
else{
int nDigits = floor(log10(abs(msgLength))) + 1;
int nDigits2 = floor(log10(abs(msgLength + nDigits + 1))) + 1;
if (nDigits2 > nDigits){
nDigits = nDigits2;
}
msgLength += nDigits + 1;
char prefix[msgLength];
sprintf(prefix, "%d|", msgLength);
strcat(prefix, msg);
// if I uncomment the below, msgWLength is returned correctly
// printf("msg: %s\n", prefix);
msgWLength = prefix;
}
return msgWLength;
}
The problem in your code is
msgWLength = prefix;
here, you're assigning the address of a local variable (prefix) to the pointer and you try to return it.
Once the function finishes execution, the local variables will go out of scope and the returned pointer will be invalid.
You need to make prefix as a pointer and allocate memory dynamically, if you want it to retain it's existence after returning from the function.
String reallocation to the exact length can be very cumbersome in C. You'd probably be much better off just using a sufficiently large buffer. Here, I use limits.h to determine the size of a line buffer according to the system (LINE_MAX):
#include <stdio.h>
#include <limits.h>
#include <string.h>
int main()
{
/* Our message */
char const msg[] = "Hello, world!";
/* Buffer to hold the result */
char buffer[LINE_MAX];
/* Prefix msg with length */
snprintf(buffer, LINE_MAX, "%lu|%s", strlen(msg)+1, msg);
/* Print result */
printf("%s\n", buffer);
return 0;
}
The following code throws the error:
mem(44582) malloc: * error for object 0x7f9f8a4000e0: pointer being freed was not allocated
* set a breakpoint in malloc_error_break to debug
Abort trap: 6
I'm not sure what's going on. I'm freeing an area of memory that I explicitly malloc'd, does it have something to do with passing in a pointer to another method?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFERSIZE 10
void readstringbuffered(char *buffer);
int main(int argc, char const *argv[])
{
char *buffer = (char *)malloc(BUFFERSIZE);
readstringbuffered(buffer);
printf("%s",buffer);
free(buffer);
return EXIT_SUCCESS;
}
void readstringbuffered(char *buffer)
{
FILE *source;
source = fopen("hello.txt","r");
int current_size = BUFFERSIZE;
int len = 0;
int c;
while((c = fgetc(source)) != EOF)
{
if(len == current_size-1)
{
current_size *= 2;
char *temp = (char *)realloc(buffer,current_size);
if(!temp)
{
fprintf(stderr,"out of memory");
exit(1);
}
buffer = temp;
}
buffer[len] = c;
len++;
}
buffer[len] = 0;
}
C is a pass by value language. The modifications you make to buffer inside your readstringbuffered() function have no effect on the value of buffer in main(). If the realloc() there is ever executed, you've already freed the buffer that main knows about, and when you return - BAM - double free.
A possible solution is to pass a pointer to buffer, rather than buffer itself. Change the signature of readstringbuffered() to be:
void readstringbuffered(char **buffer)
And then use *buffer inside it. At the call site, you'd use readstringbuffered(&buffer) to pass the necessary pointer.
realloc() can release the previously allocated memory and allocate it again somewhere else, which makes your buffer pointer in main totally invalid. You can pass buffer by reference and have readstringbuffered() modify it accordingly, or return a pointer to buffer instead of void.
The buffer pointer in main() will not be modified according to the reallocations you do in readstringbuffered(), you may write back the buffer pointer using a pointer to the buffer pointer (pBuffer), like this:
void readstringbuffered(char** pBuffer,size_t* pSize)
{
char* buffer = *pBuffer;
size_t size = MIN_SIZE;
char* newBufferPtr = (char*) realloc(buffer,size);
if(newBufferPtr)
{
buffer = newBufferPtr;
}
else
{
//out of memory
free(buffer);
buffer = NULL;
size = 0;
}
if(buffer)
{
//fill the buffer
}
//must always execute
*pBuffer = buffer;
*pSize = size;
}
int main(int argc, char const *argv[])
{
char* buffer = NULL;
size_t size = 0;
readstringbuffered(&buffer,&size);
if(buffer)
{
printf("%s",buffer);
free(buffer);
}
else
{
//error
}
return EXIT_SUCCESS;
}
I am trying to do a pretty simple thing - it is reading a file and then turning it into a char** splitting it into lines. However when I return a struct containing the char** and size i get Segmentation fault. I read here: C segmentation fault before/during return statement that it's probably "mangled stack". I still however don't know what I did to mangle it. This is my code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "comp_words.h"
#define BLOCK 4096
struct sized_str {
char* str;
long size;
};
struct sized_arr {
char** content;
int size;
};
struct sized_str readfile(char* name) {
FILE *f;
long filesize;
char *buf;
struct sized_str res;
int r, p = 0;
f = fopen(name, "r");
fseek(f, 0, SEEK_END);
filesize = ftell(f);
rewind(f);
buf = calloc(filesize + 1, sizeof(char));
while ((r = fread(buf + p, sizeof(char), BLOCK, f))) {
p += r;
}
res.str = buf;
res.size = filesize + 1;
return res;
}
struct sized_arr read_dict() {
struct sized_str file_content;
struct sized_arr result;
char *buf, *buf_cpy, *buf_cpy_point, *line, **res;
int i = 0, j, line_count = 0;
file_content = readfile("/var/tmp/twl06.txt");
buf = file_content.str;
buf_cpy = (char*)malloc(file_content.size * sizeof(char));
strcpy(buf_cpy, buf);
buf_cpy_point = buf_cpy;
while (strtok(buf_cpy_point, "\n\r")) {
line_count++;
buf_cpy_point = NULL;
}
res = (char**)malloc(sizeof(char*) * line_count);
while ((line = strtok(buf, "\n\r"))) {
res[i] = (char*)malloc(sizeof(char) * strlen(line));
j = 0;
while ((res[i][j] = tolower(line[j]))) {
j++;
}
buf = NULL;
}
free(buf_cpy);
result.size = line_count;
result.content = res;
return result;
}
// ...
int main (int argc, char** argv) {
struct sized_str input;
struct sized_arr dict;
dict = read_dict();
// ...
return 0;
The code segfaults while returning from read_dict function.
At least at first glance, this seems to have a couple of problems. First:
while ((line = strtok(buf, "\n\r"))) {
To use strtok you normally pass the buffer on the first all, then make subsequent calls passing "NULL" for the first parameter until strtok returns a NULL (indicating that it's reached the end of the buffer). [Edit: upon further examination, it's apparent this isn't really a bug -- as pointed out by #Casablanca, he sets buf to NULL in the loop so the second and subsequent iterations actually do pass NULL for the first parameter -- so the current code is a bit hard to understand and (at least arguably) somewhat fragile, but not actually wrong.]
Second, when you allocate your space, it looks like you're not allocating space for the terminating NUL:
res[i] = (char*)malloc(sizeof(char) * strlen(line));
At least at first glance, it looks like this should be:
res[i] = malloc(strlen(line)+1);
[As an aside, sizeof(char)==1 and casting the return from malloc can mask the bug of failing to #include <stdlib.h> to get a proper prototype in scope.]
Some of your other code isn't exactly wrong, but strikes me as less readable than ideal. For example:
j = 0;
while ((res[i][j] = tolower(line[j]))) {
j++;
}
This appears to be a rather obfuscated way of writing:
for (j=0; line[j] != '\0'; j++)
res[i][j] = tolower((unsigned char)line[j]);
Also note that when you call tolower, you generally need/want to cast the parameter to unsigned char (passing a negative value gives undefined behavior, and quite a few characters with accents, umlauts, etc., will normally show up as negative in the typical case that char is signed).
You also seem to have a memory leak -- read_dict calls readfile, which allocates a buffer (with calloc -- why not malloc?) and returns a pointer to that memory in a structure. read_dict receives the structure, but unless I've missed something, the struct goes out of scope without your ever freeing the memory it pointed to.
Rather than try to find and fix the problem you've seen, my immediate reaction would be to start over. It seems to me that you've made the problem considerably more complex than it really is. If I were doing it, I'd probably start with a function to allocate space and read a line into the space, something on this order:
// Warning: Untested code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *readline(FILE *file) {
char *buffer = NULL;
size_t current_size = 1;
char *temp;
const int block_size = 256;
do {
if (NULL == (temp = realloc(buffer, current_size+block_size)))
break;
buffer = temp;
buffer[current_size-1] = '\0';
if (fgets(buffer+current_size-1, block_size, file)==NULL)
return strlen(buffer) > 0 ? buffer : NULL;
current_size += block_size-1;
} while (strchr(buffer, '\n') == NULL);
strtok(buffer, "\n");
if (NULL != (temp = realloc(buffer, strlen(buffer)+1)))
buffer =temp;
return buffer;
}
Once that's working, reading all the lines in the file and converting them to upper-case comes out something like:
// Warning: more untested code.
while (res[i] = readline(file)) {
size_t j;
for (j=0; res[i][j]; j++)
res[i][j] = toupper((unsigned char)res[i][j]);
++i;
}
It looks like you forgot to increment i after storing each line into the result array, so you end up storing all lines into res[0]. But you still set result.size = line_count at the end, so all array elements beyond the first are undefined. An i++ at the end of this loop: while ((line = strtok(buf, "\n\r"))) should fix it.