Passing an array of strings without having contents modified - c

I have been trying to pass an array of strings into a function that finds all of the IP addresses of the host. My problem is immediately after I fill the array up with the addresses the contents are changed unexpectedly. I print the contents of the array immediately after I assign a string to one part of the array, this is how I know I am initializing the array. Then after the loop is done I try accessing all of the addresses in the array and all of the values are changed to the value I last passed into the array. Why is this? What am I doing wrong?
Here is the function:
static int getHostIP(char*ip_list[])
{
char hostName[80];
if(gethostname(hostName, sizeof(hostName)) == SOCKET_ERROR)
{
printf("Error %s when getting host name.\n", WSAGetLastError());
return 1;
}
printf("Hostname: %s\n", hostName);
struct addrinfo *result = NULL;
if(getaddrinfo(hostName,NULL, NULL, &result) == 1)
{
printf("Error %s when getting host address info.\n", WSAGetLastError());
return 1;
}
//iterate over IP addresses
struct addrinfo *ptr;
int x = 0;
for(x = 0,ptr = result; ptr != NULL;ptr = ptr->ai_next, x++)
{
struct sockaddr_in *hostaddr = (struct sockaddr_in*)ptr->ai_addr;
char ip_addr[80];
inet_ntop(ptr->ai_family,(void*)&hostaddr->sin_addr, ip_addr, sizeof(ip_addr));
ip_list[x] = ip_addr;
}
int i;
for(i = 0; i < 7;i++)
{
printf("IP: %s\n", ip_list[i]);
}
return 0;
}
EDIT
Calling code:
char * ip_list[80] = {0};
//TODO: Get Host IP address
if(getHostIP(ip_list) == 1) return 1;

The behaviour you are experiencing is caused by the variable ip_addr which is always pointing to the same buffer in the stack during each iteration. Thus, all pointers in ip_list are pointing to the same buffer which contains the value calculated in the last iteration of the loop.
If you allocate this buffer in the heap by using malloc the problem should be solved because,now the loop block will create a new buffer for each ip. For example :
#define BUFFER_SIZE 80 // no in the function body
char * ip_addr = NULL;
for(x = 0,ptr = result; ptr != NULL;ptr = ptr->ai_next, x++)
{
ip_addr = malloc(BUFFER_SIZE);
struct sockaddr_in *hostaddr = (struct sockaddr_in*)ptr->ai_addr;
inet_ntop(ptr->ai_family,(void*)&hostaddr->sin_addr, ip_addr, BUFFER_SIZE);
ip_list[x] = ip_addr;
}

How is your data allocated ?
Try with:
static int getHostIP(char**ip_list)

Are you properly initializing the array you are passing in to this function. You are declaring an input of an array of char pointers. When ever you pass an array in c you must also pass along the length the array was initialized with. The memory needs to live somewhere and be reserved by the system.
Can you please provide the calling code so we can see what you are doing wrong.
Alternatively --- you could pass this entire array byref so you would just be getting an out pointer and the array would be declared by this function. Since you have no idea how many IP addresses you might match that might be a superior design.

Related

C - How to add a struct element to a dynamically allocated array of structs?

Trying to add another element to a struct array in C (Windows specific, using VS2019 Community). Works fine, until I try to assign the return value of realloc to the original array. The code in main (declarations and initialization, as well as calling code) is as follows:
// server.h
struct server {
wchar_t* name;
wchar_t ip_address[16];
int port;
};
// main.c
static int nb_servers = 0;
static struct server* servers = NULL;
void add_server(wchar_t* name, wchar_t ip_address[16], wchar_t* port)
{
struct server newserver;
newserver.name = name;
wcsncpy(newserver.ip_address, ip_address, 16);
char* port_char = malloc(6);
if (port_char == NULL) {
exit(EXIT_FAILURE);
}
size_t i;
wcstombs_s(&i, port_char, 6, port, _TRUNCATE);
int port_int = 0;
str2int(&port_int, port_char, 10);
newserver.port = port_int;
// add to servers
nb_servers = server_add(&servers, &newserver, nb_servers);
}
Then in another file, this is where I try to add the new server to the list:
// server.c
int server_add(struct server** servers, struct server* myserver, int nb_servers)
{
struct server* tmp = (struct server*) realloc(*servers, (nb_servers + 1) * sizeof(struct server));
if (tmp == NULL) {
exit(EXIT_FAILURE);
}
tmp[nb_servers].name = (wchar_t*) calloc(strlen(myserver->name), sizeof(wchar_t));
if (tmp[nb_servers].name == NULL) {
exit(EXIT_FAILURE);
}
wcsncpy(tmp[nb_servers].name, myserver->name, strlen(myserver->name));
wcsncpy(tmp[nb_servers].ip_address, myserver->ip_address, 16);
tmp[nb_servers].port = myserver->port;
*servers = tmp; // this only copies the first value [0]
// also tried **servers = *tmp and other combinations, nothing seems to work.
return ++nb_servers;
}
But only the first value is 'copied', or rather only servers[0] point to a valid object. However, tmp[0] to tmp[nb_servers - 1] are valid and contain the correct data. I'm using a similar reallocation mechanism to shrink the array in a remove_server method and that same reassignment works in that case.
Question:
How to correctly add a struct item to an array of structs by dynamically reallocating memory?

How to malloc modbus_t

I write generic application for handle as many modbus devices as defined in JSON config file.
mbus_servers struct used in my_modbus_init() contents ip of device and port.
Initialization of one modbus_t in my_modbus_init() looks like this:
modbus_t * my_modbus_init(const char * ip_s, int port, int slave_id)
{
modbus_t *ctx;
ctx = modbus_new_tcp(ip_s, port);
if(ctx == NULL)
{
printf("Error");
}
modbus_set_debug(ctx, 0);
if (modbus_connect(ctx) == -1)
{
fprintf(stderr, "Connection failed: %s\n",modbus_strerror(errno));
modbus_free(ctx);
return NULL;
}
modbus_set_slave(ctx, slave_id);
return ctx;
}
Now I try to initialize dynamiclly allocated number of modbus_t:
modbus_t * my_modbus;
int quantity_of_connections_modbus = 3;
my_modbus = (modbus_t *) malloc (quantity_of_connections_modbus * sizeof(modbus_t));
^here I get invalid application of ‘sizeof’ to incomplete type ‘modbus_t' (I know that is because i dont have acces to definition of modbus_t [it is defined in modbus.h as typedef struct _modbus modbus_t; ])
for(i=0; i< quantity_of_connections_modbus; i++)
{
// |> my_modbus[i] = my_modbus_init(mbus_servers[i]->host,mbus_servers[i]->port,MBUS_SLAVE);
// |- And here error: dereferencing pointer to incomplete type ‘modbus_t {aka struct _modbus}’
}
Is there any way to create as many modbus_t as needed using malloc?
Instead of having an array of modbus_t objects, have an array of pointers to modbus_t objects. This makes sense since the my_modbus_init function (and the modbus_new_tcp function it calls) returns pointers.
In other words change sizeof(modbus_t) to sizeof(modbus_t *). And change the variable my_modbus to represent this array of pointers (i.e. be a modbus_t **).
The code from the question modified accordingly:
modbus_t ** my_modbus;
int quantity_of_connections_modbus = 3;
my_modbus = malloc (quantity_of_connections_modbus * sizeof(modbus_t*));
for(i=0; i< quantity_of_connections_modbus; i++)
{
my_modbus[i] = my_modbus_init(mbus_servers[i]->host,mbus_servers[i]->port,MBUS_SLAVE);
}

How to store data in a dynamic array of structs?

I have these structs with which I would like to implement a map
typedef struct {
const char *name;
int number;
} Entry;
typedef struct {
int available;
int guard;
Entry *entries;
} Map;
and code to work to initialise and put elements in it:
Map *map_init() {
Map *res = (Map *) malloc(sizeof(Map));
res->available = 4;
res->guard = 0;
res->entries = (Entry *) malloc(4 * sizeof(Entry));
return res;
}
int map_put(Map *map, const char *name, int nr) {
Entry entry;
int i = 0;
for (i = 0; i < map->guard; ++i) {
entry = map->entries[i];
printf("entry ( x , %u) at %p (%p)\n", entry.number, &entry, entry.name);
if (!strcmp(entry.name, name)) // Segmentation fault here
return 0;
}
entry = map->entries[map->guard++];
entry.name = name;
entry.number = nr;
printf("entry (%s, %u) at %p (%p)\n", entry.name, entry.number, &entry, entry.name);
return 1;
}
when I run my main method
int main(int argc, char **argv) {
printf("Initialising...\n");
Map *map = map_init();
printf("Putting...\n");
map_put(map, "test", 2);
map_put(map, "some", 1);
// ...
free(map->entries);
free(map);
return 0;
}
I get as output
Initialising...
Putting...
entry (test, 2) at 0x7fff50b32a90 (0x10f0cdf77)
entry ( x , 0) at 0x7fff50b32a90 (0x5000000000000000)
Segmentation fault: 11
from which I could derive that the segmentation fault is due to the fact that entry.name does not point to a string anymore (also the number is lost, but this does not lead to unauthorised memory access). After I set the data in the first invocation of map_put, everything seems to be stored in the correct places.
Anyone an idea where these entries could be overwritten or why the values are not stored?
The problem is this:
entry = map->entries[map->guard++];
Here you copy the data from the array into the entry structure instance. Then you modify the data of entry and discard those modifications. The (original) structure data in the array is still unmodified.
That will of course lead to undefined behavior when you in the next call to map_put use the uninitialized structures in the array.
Either modify the array structure instance directly and increase map->guard separately. Or make entry a pointer and make it point to the array element.
The problem is that variable entry in map_put is not a pointer. It is a structure. So the code
entry = map->entries[map->guard++];
entry.name = name;
entry.number = nr;
copies the contents of map->entries[map->guard] into entry. Then you update the fields in entry and return from the function.
The correct code looks like this
int map_put(Map *map, const char *name, int nr) {
Entry *entry; // <-- entry is a pointer
int i = 0;
for (i = 0; i < map->guard; ++i) {
entry = &map->entries[i];
printf("entry ( x , %u) at %p (%p)\n", entry->number, (void *)entry, (void *)entry->name);
if (!strcmp(entry->name, name))
return 0;
}
entry = &map->entries[map->guard++];
entry->name = name;
entry->number = nr;
printf("entry (%s, %u) at %p (%p)\n", entry->name, entry->number, (void *)entry, (void *)entry->name);
return 1;
}
You have a major problem in map_put. You use a local Entry, in which you copy entries from the map. But when you later assign value to the local copy, the original entries from the map are left unchanged.
So when you later try to compare the new name to the existing entry, you are comparing it to uninitialized values, which is Undefined Behaviour.
You should use an Entry * instead:
int map_put(Map *map, const char *name, int nr) {
Entry *entry;
int i = 0;
for (i = 0; i < map->guard; ++i) {
entry = map->entries + i;
printf("entry ( x , %u) at %p (%p)\n", entry->number, entry, entry->name);
if (!strcmp(entry->name, name)) // Segmentation fault here
return 0;
}
entry = &map->entries[map->guard++];
entry->name = name;
entry->number = nr;
printf("entry (%s, %u) at %p (%p)\n", entry->name, entry->number, entry, entry->name);
return 1;
}
But that is not all. You just store the address of a string in name. It is fine in this example, because you are actually passing string litteral constants. But if you read strings from standard input or a file, the content of the buffer will be overwritten with each new value. As you only store the address, you will end with all entries pointing to same value: the last one.
IMHO you should comtemplate using strdup to store copies of the string - and free them at the end. BTW, as you have an init function to initialize you Map, you should build a cleanup one to have all necessary free in one single place.

realloc() on array of structs gives invalid next size

I have this function. As you can see, everything is being done in the function, I'm not allocating in the main and then passing anything to it (I'll only return the pointer to the array once the function is done). The function in itself (with a fixed size for the array) works, but the realloc fails.
struct database *parse() {
int i = 0;
int n = 1;
FILE *dbase = (fopen(PATH, "r"));
if (dbase == NULL) {
fprintf(stderr, ERRORE_APERTURA);
exit(EXIT_FAILURE);
}
struct database *database_array = calloc(20*n, sizeof(struct database));
if (database_array == NULL) {
fprintf(stderr, "Impossibile allocare memoria\n");
exit(EXIT_FAILURE);
}
while (feof(dbase) == 0) {
fscanf(dbase, "%[^:]:%[^:]:\n", database_array[i].user, database_array[i].password);
database_array[i].iswritten = 1;
i++;
if (i > 20*n) {
n++;
struct database *new_database_array = realloc(database_array, sizeof(struct database)*(20*n));
database_array = new_database_array;
}
}
database_array[++i].iswritten = 0;
fclose(dbase);
return database_array;
}
I tried reading other explanations, but I can't understand what's wrong here.
The array I allocated with calloc is initially 20. then, when it's filled, I want it to double in size, so I use n, which will be 2, by 20, so 40.
The frustrating thing is that I tried reallocating an array of struct with a simpler program, and doing THE SAME THING works without any problem:
#include <stdio.h>
#include <stdlib.h>
struct prova {
int a;
int b[10];
};
int main() {
struct prova* array_struct = calloc(10, sizeof(struct prova));
array_struct[0].a = 2;
struct prova* tmp = realloc(array_struct, sizeof(struct prova) * 20);
free(array_struct);
array_struct = tmp;
array_struct[1].b[1] = 3;
printf("a = %d", array_struct[0].a);
printf("b = %d\n", array_struct[1].b[1]);
return 0;
}
What am I not seeing? (Please nevermind the fact that I'm not checking if realloc returns NULL, I'll add that later)
struct database *new_database_array = realloc(database_array, sizeof(struct database)*(20*n));
free(database_array);
You can't both reallocate something and deallocate it. You can do either, but once you've done either, the previous allocation no longer exists, so you can't do the other.
After the first line of code above, the value of database_array should not be used anymore because it may not be valid.

C programming pointers and char array problems

I want to pass the contents of an array to another method and have that method print out the entire array - how would i do this?
Currently:
I'm returning an array from a function.
char* search_value(struct PDB *llist)
{
int realID = -7;
int x = 0;
int task = 0;
char *received;
char theMessage[100];
theMessage[0] = '\0';
printf("Your choice: `Search'\n");
printf("Enter the value you want to find: ");
scanf("%d", &task);
while(llist->data1 != NULL)
{
if(task == llist->taskID)
{
realID = llist->taskID;
strcpy(theMessage, llist->data1);
break;
}
}
return theMessage;
}
i'm getting the return value:
void getMessage(const int GET_MESSAGE)
{
char * received = NULL;
int x = 0;
received = search_value(llist);
printf("%s", received);
}
I want to somehow print the entire value (rather than just the first value to which the pointer is pointing at - how would i do this?
A few corrections and it should work:
// - struct contents shouldn't be changed by the function, make its pointer const.
// - pass a pointer to an allocated array as parameter
char* search_value(const struct PDB *llist, char* theMessage)
{
int realID = -7;
int x = 0;
int task = 0;
char *received;
theMessage[0] = '\0';
printf("Your choice: `Search'\n");
printf("Enter the value you want to find: ");
scanf("%d", &task);
while(llist->data1 != NULL)
{
if(task == llist->taskID)
{
realID = llist->taskID;
strcpy(theMessage, llist->data1);
break;
}
}
return theMessage;
}
void getMessage(const int GET_MESSAGE)
{
char received[100]; // allocate the array outside the function
int x = 0;
search_value(llist, received); // pass a pointer to the first element
printf("%s", received);
}
You have an issue with variable scope here: theMessage is local to the function search_value, so you're returning a pointer to an array which no longer exists once the function completes.
Instead you should use malloc() to allocate the space for theMessage and then subsequently free() it later on outside of the function when you're finished with it —  however this can often lead to memory leaks if you're not diligent about cleaning up after yourself.
You can allocate the memory like so:
char * message = malloc(100);
One alternative would be to allocate the buffer in getMessage() and pass a pointer to the buffer into search_value which could then write into it:
void getMessage(const int GET_MESSAGE)
{
char received[100];
int x = 0;
search_value(llist, received);
printf("%s", received);
}
void search_value(struct PDB *llist, char * buffer)
{
// write to buffer
}
Another option is to declare a char * pointer inside getMessage(), pass a pointer to a pointer into search_value() and again use malloc() to allocate space for the buffer.
Finally, this is a minor style criticism, but you'd do well to learn to stick to one convention for naming your functions, search_value and getMessage are not consistent names, and this will irk many a coder that you work with.
You have several problems with your code. I'm guessing that you want to search a list for some value, then return that value.
The first problem is that you do not actually iterate over the list, but only check the same item over and over again. The other problem is that you return a pointer to a local variable. This is undefined behavior, because as soon as the function returns the memory the pointer points to can be used for something else.
I suggest you change your code as follows:
char *search_value(struct PDB *llist, char *theMessage, size_t theMessageMaxLength)
{
int realID = -7;
int task = 0;
printf("Your choice: `Search'\n");
printf("Enter the value you want to find: ");
scanf("%d", &task);
while(llist != NULL && llist->data1 != NULL)
{
if(task == llist->taskID)
{
realID = llist->taskID;
strncpy(theMessage, llist->data1, theMessageMaxLength);
theMessage[theMessageMaxLength] = '\0';
break;
}
llist = llist->next; /* Assuming the field is named "next" */
}
return theMessage;
}
void getMessage(const int GET_MESSAGE)
{
char *received = NULL;
char theMessage[100];
/* Subtract 1 from the size, for the terminating '\0' */
received = search_value(llist, theMessage, sizeof(theMessage) - 1);
printf("%s", received);
}
the array you are returning is local to that function. Either the calle function shall provide the array in which it expects the values or use static array.

Resources