I am trying to create a dynamic array of Clients, but i am not succeding. This is my code. When i run this code the output is
3
� H
3
4332
3
8939
I think it's printing memory stuff, however i don't know why. I put my code down here
int client_counter = 0;
typedef struct client
{
char *pid;
char *message;
}Client;
void store (Client * client_array, char *buf)
{
Client c;
c.pid = strdup (strtok (buf, ":"));
c.message = strdup (strtok (NULL, "\0"));
client_array[client_counter++] = c;
}
int main () {
Client* client_array = malloc (sizeof (struct client));
char buf1[50] = { "1245:message" };
store (client_array, buf1);
char buf2[50] = { "4332:message" };
store (client_array, buf2);
char buf3[50] = { "8939:message" };
store (client_array, buf3);
for (int i = 0; i < client_counter; i++)
{
printf ("%d\n", client_counter);
printf ("%s\n", client_array[i].pid);
}
return 0;
}
I already tried do use this:
client_array = realloc(client_array, sizeof(struct client) * (client_counter + 1));
in store function right after this line.
client_array[client_counter++] = c;
But it's not working too.
You need to allocate extra memory if there's not enough space. Right now, you allocate enough for one, but you try to access three.
Don't forget to return the pointer of the new memory block back to main! In the following, this is done by passing a pointer to the caller's pointer. store modifies the caller's pointer via the passed pointer.
// Sets errno and returns 0 on error.
int store(Client ** client_array_ptr, char *buf) {
Client* new_client_array = realloc(*client_array_ptr, sizeof(Client) * (client_counter + 1));
if (!new_client_array)
return 0;
*client_array_ptr = new_client_array;
// ...
new_client_array[client_counter++] = c;
return 1;
}
int main() {
Client* client_array = NULL;
// ...
if (!store(&client_array, buf1)) {
perror("malloc");
exit(1);
}
// ...
if (!store(&client_array, buf2)) {
perror("malloc");
exit(1);
}
// ...
free(client_array);
return 0;
}
The original code does out-of-range access because it is trying to store multiple data in a buffer which is allocated for only one element.
To use realloc(), you have to note that arguments of functions in C are copies of what are passed. Modifying arguments inside callee function do not affect what is passed in caller. You should pass pointers to what should be modified to have functions modify caller's local things.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int client_counter = 0;
typedef struct client
{
char *pid;
char *message;
}Client;
void store (Client ** client_array, char *buf)
{
Client c;
c.pid = strdup (strtok (buf, ":"));
c.message = strdup (strtok (NULL, "\0"));
*client_array = realloc(*client_array, sizeof(struct client) * (client_counter + 1));
(*client_array)[client_counter++] = c;
}
int main () {
Client* client_array = malloc (sizeof (struct client));
char buf1[50] = { "1245:message" };
store (&client_array, buf1);
char buf2[50] = { "4332:message" };
store (&client_array, buf2);
char buf3[50] = { "8939:message" };
store (&client_array, buf3);
for (int i = 0; i < client_counter; i++)
{
printf ("%d\n", client_counter);
printf ("%s\n", client_array[i].pid);
}
return 0;
}
I would do it a bit different way.
typedef struct
{
char *pid;
char *message;
}client_TypeDef;
typedef struct
{
size_t size;
client_TypeDef clients[];
}clients_TypeDef;
clients_TypeDef *add(clients_TypeDef *clients, const char *pid, const char *message)
{
size_t newsize = clients ? clients -> size + 1 : 1;
client_TypeDef client = {.pid = strdup(pid), .message = strdup(message)};
if(client.pid && client.message)
{
clients = realloc(clients, sizeof(*clients) + newsize * sizeof(clients -> clients[0]));
if(clients)
{
clients -> size = newsize;
clients -> clients[newsize - 1] = client;
}
}
else
{
free(client.pid);
free(client.message);
clients = NULL;
}
return clients;
}
Related
I've having a segmentation fault error in my program. This is the code: for first, I've a struct:
struct Slave
{
char **all_samples;
int number_of_samples;
char **last_samples;
int **RSSI;
int *AGC;
int *AUTH;
};
Then I've a function: (debbugging I'm sure that the segmentation fault occurs when I call RSSI function).
all_samples and last_samples are 2 arrays. the first contains N string (N is variable), while the second surely contains 4 strings.
struct Slave *read_slaves_file(char *file_path, char *slave)
{
...
char **all_samples = malloc(N * sizeof(char *));
char **last_samples = malloc(4 * sizeof(char *));
struct Slave *slave_ptr = malloc(sizeof(struct Slave *));
slave_ptr->last_samples = last_samples;
slave_ptr->all_samples = all_samples;
slave_ptr->number_of_samples = i;
slave_ptr->RSSI = RSSI(slave_ptr->last_samples);
return slave_ptr;
}
and this is RSSI function:
it simply parse a string to extract the number after the -RSSI word. For example:
2022-10-14 8:51:17:708 -IP 192.168.101.11 -RSSI 88367 -AGC 429496720 -AUTH 0
It extracts 88367. It works on 4 strings like this one.
int **RSSI(char **last_samples)
{
int **rssi_value = malloc(sizeof(int *) * 128);
char string[128];
const char s[16] = " ";
char *token;
int i;
for (int k = 0; k < 4; k++)
{
strcpy(string, last_samples[k]);
token = strtok(string, s);
i = 0;
while (token != NULL)
{
if (i == 5)
{
rssi_value[k] = atoi(token);
}
i++;
token = strtok(NULL, s);
}
}
return rssi_value;
}
Into main.c:
#include "lib.h"
int main()
{
while (true)
{
...
struct Slave *slave_1 = read_slaves_file(FILE_PATH, SLAVE_1);
free(slave_1->last_samples);
free(slave_1->all_samples);
free(slave_1->RSSI);
free(slave_1);
usleep(1000*1000);
}
return 0;
}
This memory allocation is already invalid
struct Slave *slave_ptr = malloc(sizeof(struct Slave *));
^^^^^^^^^^^^^^
You need to write
struct Slave *slave_ptr = malloc(sizeof(struct Slave));
^^^^^^^^^^^^^^
or
struct Slave *slave_ptr = malloc(sizeof( *slave_ptr ));
^^^^^^^^^^^^^
Also in this for loop
for (int k = 0; k < 4; k++)
{
strcpy(string, last_samples[k]);
//...
the call of strcpy uses uninitialized pointers last_samples[k].
And this statement
rssi_value[k] = atoi(token);
is also incorrect. There is an attempt to initialize a pointer with an integer.
I've defined a struct to represent strings and want to make a list from this string-structs. I've coded a function toString, which gets a char pointer and the result is such a string-struct. I've coded a function toList, which gets a pointer of char pointer, makes strings from these char pointers and concatenate these to a list of strings.
Now I want to use these, but I always get this stack error 0 [main] stringL 1123 cygwin_exception::open_stackdumpfile: Dumping stack trace to stringL.exe.stackdump. Could the problem be the assignment with makro? Not even the debug output 0, 1, 2, 3 is printed. I'm thankful for some help.
Code:
#include<stdio.h>
#include<stdlib.h>
#define EMPTYLIST NULL
#define ISEMPTY(l) ((l) == EMPTYLIST)
#define TAIL(l) ((l)->next)
#define HEAD(l) ((l)->str)
typedef struct {
char *str;
unsigned int len;
} String;
typedef struct ListNode *StringList;
struct ListNode {
String str;
StringList next;
};
String toString (char *cstr) {
String res = {NULL, 0};
res.str = malloc(sizeof(char));
char *ptr = res.str;
while(*cstr) {
*ptr++ = *cstr++;
res.str = realloc(res.str, sizeof(char) * (res.len +2));
res.len++;
}
*ptr = '\0';
return res;
}
StringList toList (char **cstrs, unsigned int sc){
if(sc > 0) {
StringList res = malloc(sizeof(*res));
HEAD(res) = toString(*cstrs);
TAIL(res) = toList(cstrs+1, sc+1);
}
return EMPTYLIST;
}
int main() {
printf("0");
char **strs = malloc(sizeof(**strs) *2);
unsigned int i = 0;
char *fst = "Der erste Text";
char *snd = "Der zweite Text";
printf("1");
StringList res = toList(strs, 2);
StringList lstPtr = res;
strs[0] = malloc(sizeof(char) * 15);
strs[1] = malloc(sizeof(char) * 16);
printf("2");
while(*fst) {
strs[0][i] = *fst++;
i++;
}
printf("3");
i = 0;
while(*snd) {
strs[1][i] = *snd++;
i++;
}
printf("Liste: \n");
for(i = 0; i < 2; i++){
printf("Text %d: %s\n", i, HEAD(lstPtr++));
}
return 0;
}
After this statement
res.str = realloc(res.str, sizeof(char) * (res.len +2));
the value stored in the pointer res.str can be changed. As a result the value stored in the pointer ptr after its increment
*ptr++ = *cstr++;
can be invalid and does not point to a place in the reallocated memory.
Here is my problem: I have to make this program for school and I spent the last hour debugging and googling and haven't found an answer.
I have an array of structures in my main and I want to give that array to my function seteverythingup (by call by reference) because in this function a string I read from a file is split up, and I want to write it into the structure but I always get a SIGSEV error when strcpy with the struct array.
This is my main:
int main(int argc, char *argv[])
{
FILE* datei;
int size = 10;
int used = 0;
char line[1000];
struct raeume *arr = (raeume *) malloc(size * sizeof(raeume*));
if(arr == NULL){
return 0;
}
if(argc < 2){
return 0;
}
datei = fopen(argv[1], "rt");
if(datei == NULL){
return 0;
}
fgets(line,sizeof(line),datei);
while(fgets(line,sizeof(line),datei)){
int l = strlen(line);
if(line[l-1] == '\n'){
line[l-1] = '\0';
}
seteverythingup(&line,arr,size,&used);
}
ausgabeunsortiert(arr,size);
fclose(datei);
return 0;
}
and this is my function:
void seteverythingup(char line[],struct raeume *arr[], int size,int used)
{
char *token,raumnummer[5],klasse[6];
int tische = 0;
const char c[2] = ";";
int i=0;
token = strtok(line, c);
strcpy(raumnummer,token);
while(token != NULL )
{
token = strtok(NULL, c);
if(i==0){
strcpy(klasse,token);
}else if(i==1){
sscanf(token,"%d",&tische);
}
i++;
}
managesize(&arr[size],&size,used);
strcpy(arr[used]->number,raumnummer);
strcpy(arr[used]->klasse,klasse);
arr[used]->tische = tische;
used++;
}
Edit: Since there is more confusion I wrote a short program that works out the part you are having trouble with.
#include <cstdlib>
struct raeume {
int foo;
int bar;
};
void seteverythingup(struct raeume *arr, size_t len) {
for (size_t i = 0; i < len; ++i) {
arr[i].foo = 42;
arr[i].bar = 53;
}
}
int main() {
const size_t size = 10;
struct raeume *arr = (struct raeume*) malloc(size * sizeof(struct raeume));
seteverythingup(arr, size);
return 0;
}
So basically the signature of your functions is somewhat odd. Malloc returns you a pointer to a memory location. So you really dont need a pointer to an array. Just pass the function the pointer you got from malloc and the function will be able to manipulate that region.
Original Answer:
malloc(size * sizeof(raeume*));
This is probably the part of the code that gives you a hard time. sizeof returns the size of a type. You ask sizeof how many bytes a pointer to you raeume struct requires. what you probably wanted to do is ask for the size of the struct itself and allocate size times space for that. So the correct call to malloc would be:
malloc(size * sizeof(struct raeume));
I'm fiddling around with Object oriented programming in C (note! Not C++ or C# - just plain ol' C). Right now, I'm trying to dynamically resize a struct (I'm playing with writing a simple String class). The code builds okay:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct TestClass
{
char *s;
size_t size;
size_t b_size;
void (*CreateString) (struct TestClass*,char*);
};
void TestClassCreateString(struct TestClass *m, char* str)
{
char *buf;
m->size = strlen(str);
if (!m->size)
{
free(m->s);
m->s = malloc(16);
}
else
{
buf = realloc(m->s, m->size);
if (buf) m->s = buf;
}
}
struct TestClass* TestClassCreate()
{
struct TestClass* m = malloc((sizeof(struct TestClass)));
m->CreateString = TestClassCreateString;
return m;
}
int main()
{
struct TestClass* fizz = TestClassCreate();
fizz->CreateString(fizz,"Hello World");
free(fizz);
return 0;
}
…But on running it I get the following error:
malloc: *** error for object 0x5000000000000000: pointer being realloc'd was not allocated
*** set a breakpoint in malloc_error_break to debug
Is anyone able to identify where I've gone wrong? Thanks in advance!
malloc does not zero its memory; it returns garbage, so you get an invalid pointer inside this struct:
struct TestClass* m = malloc((sizeof(struct TestClass)));
When creating a struct TestClass in TestClassCreate() the code misses to properly initialise the freshly allocated struct.
So calling
free(m->s);
tries to free memory at a random address, which invokes undefined behaviour and typically crashes the program.
To fix this modify the code as follows
struct TestClass* TestClassCreate()
{
struct TestClass* m = ...
...
m->s = NULL;
m->size = 0;
m->b_size = 0;
return m;
}
To make things better also add some error checking:
struct TestClass* TestClassCreate()
{
struct TestClass * m = malloc((sizeof(struct TestClass)));
if (NULL != m)
{
m->CreateString = TestClassCreateString;
m->s = NULL;
m->size = 0;
m->b_size = 0;
}
return m;
}
To make the code even more fail-safe apply these last changes:
struct TestClass* TestClassCreate(void)
{
struct TestClass * m = malloc(sizeof *m);
...
Further more the code misses to allocate memory for the C-"string"'s 0-terminator here:
void TestClassCreateString(struct TestClass *m, char* str)
{
...
else
{
buf = realloc(m->s, m->size + 1); /* allocate 1 byte more for the trailing
`0` marking the end of a C-"string". */
...
You are short by 1-byte. You need to add 1 to m->size for the null-terminator if you intend to copy str to m->s. E.g.:
void TestClassCreateString(struct TestClass *m, char* str)
{
char *buf;
m->size = strlen(str);
if (!m->size)
{
free(m->s);
m->s = malloc(16);
}
else
{
buf = realloc(m->s, m->size + 1);
if (buf) m->s = buf;
strncpy (m->s, str, m->size + 1);
}
}
Then you can do something like:
int main()
{
struct TestClass* fizz = TestClassCreate();
fizz->CreateString(fizz,"Hello World");
printf ("\n fizz->s : %s\n\n", fizz->s);
free(fizz);
return 0;
}
and get:
$ ./bin/oo_struct
fizz->s : Hello World
I am learning C, and am have a problem finding out how i can free my malloc()'s.
The program runs correctly.. but im Using valgrind and it is coming up with 8 allocs and 5 frees. I need to be able to free 3 more. I commented where I believe which I am not freeing but I am not sure of a solution.
Is there a way I can free up those allocs, or do I need to consider re-writing the tokenizer()?
Here is the code to the whole file.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char *substr(const char *s, int from, int nchars) {
char *result = (char *) malloc((nchars * sizeof(char))+1);
strncpy(result, s+from, nchars);
return result;
}
/**
Extracts white-space separated tokens from s.
#param s A string containing 0 or more tokens.
#param ntokens The number of tokens found in s.
#return A pointer to a list of tokens. The list and tokens must be freed
by the caller.
*/
char **tokenize(const char *s, int *ntokens) {
int fromIndex = 0;
int toIndex = 0;
char **list;
int finalCount = *ntokens;
int count = 0;
list = malloc(*ntokens * sizeof(char*));
while ( count < finalCount) {
char *m = strchr(s,' ');
toIndex = m - s;
if(toIndex >= 0) {
list[count] = substr(s,fromIndex,toIndex); // This substr() gets free'ed from main()
s = substr(s, toIndex+1, strlen(s)); // I believe This is where I am making extra mallocs that are not being freed
count++;
} else {
list[count] = substr(s,fromIndex,strlen(s)); // This substr() gets free'ed from main()
count++;
}
}
return list;
}
int main(int argc, char **argv) {
char **list;
char *string = "terrific radiant humble pig";
int count = 4; // Hard-Coded
list = tokenize(string, &count);
for (int i=0;i<count;i++) {
printf("list[%d] = %s\n", i, list[i]);
}
// Free mallocs()'s
for (int i=0;i<count;i++) {
free(list[i]);
}
// Free List
free(list);
return 0;
}
You don't need substr s everytime after getting one token. This is too wasteful, in terms of both time and spape. You can just change the value of s to make it point to the string you need.
//s = substr(s, toIndex+1, strlen(s)); // You don't need have to generate a new string
s = s + toIndex + 1;//You can just change the value of s to make it point to the string you need
The problem is exactly where you thought it was!
Luckily in c is very easy to move the point , at which a string, you do not need to call again substr; because of pointers ;-)
// s = substr(s, toIndex+1, strlen(s));
s += toIndex+1;
A simple workaround I can think of, by just storing the current value of s in another pointer before you overwrite. And also make sure not to free the first value of s got directly as the parameter to tokenize().
char **tokenize(const char *s, int *ntokens) {
int fromIndex = 0;
int toIndex = 0;
char **list;
int finalCount = *ntokens;
int count = 0;
bool firstTime = true; // Use this to make sure you do not free up the memory for the initial s passed as the function arg
list = malloc(*ntokens * sizeof(char*));
while ( count < finalCount) {
char *m = strchr(s,' ');
toIndex = m - s;
if(toIndex >= 0) {
const char* previous_s = s; // Store the current value of s
list[count] = substr(s,fromIndex,toIndex); // This substr() gets free'ed from main()
s = substr(previous_s, toIndex+1, strlen(previous_s));
if (!firstTime)
{
free(previous_s); // Since we're done with the previous_s, we can free up the memory
}
firstTime = false;
count++;
} else {
list[count] = substr(s,fromIndex,strlen(s)); // This substr() gets free'ed from main()
count++;
}
}
if (!firstTime)
{
free(s); // There could be a block allocated last time which needs to be freed as well
}
return list;
}