Using an array of structures with call by reference - c

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));

Related

function to clear malloc, and make pointer to null

in my last question, I've asked how to use function to free an malloc'ed array, I wanted to improve my code so that the function won't just free the memory but also will set the pointer to NULL once it finishes the clearing.
Also I want a single function to do both - setting and clearing, depending on the command I'm passing, this is what I've done so far:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint-gcc.h>
char **set_arr(int number, char *command);
int command_read(char *command);
void clear_arr(char *arr[], int size);
char set[] = "set";
char clear[] = "clear";
int main() {
int num = // get number from user;
char** my_arr = NULL;
my_arr = set_arr(num, set);
// so far the code works as excepted
set_arr((size_t)&my_arr, clear);
return 0;
}
int command_read(char *command) {
if (strcmp(command, set) == 0)
return 'S';
if (strcmp(command, clear) == 0)
return 'C';
}
char **set_arr(int number, char *command) {
static char **arr = NULL;
static int size;
switch (command_read(command)) {
case 'S':
size = (int)number;
arr = malloc((size + 1) * sizeof(char *));
for (int i = 0; i <= size; i++) {
arr[i] = NULL;
if (i == size)
break;
arr[i] = malloc((string_len) * sizeof(char));
}
break;
case 'C':
clear_arr(arr, size);
free(arr);
uintptr_t value = number;
uint64_t *temp = (void *)value;
*temp = 0x0;
break;
}
return arr;
}
void clear_arr(char *arr[], int size) {
for (int i = 0; i < size; i++) {
free(arr[i]);
arr[i] = NULL;
}
}
I know that there is better methods to clear (and allocate memory?) but my primary question is, did I free all the memory I allocated for the array, and after the clearing, does the pointer my_arr is set correctly to NULL?
Writing a generic function to achieve your goal is not possible in Standard C because pointers to different types of objects may have a different representation so you cannot pass the address of a pointer and expect the function to handle it in a generic manner.
Yet this provision in the C Standard is not used on most current systems today. In particular, the POSIX standard mandates that all pointers have the same representation. Hence your generic function can work on these systems, with some precautions to avoid compilation warnings:
// free an array of allocated things
void free_array(void ***p, size_t count) {
void **array = *p;
for (size_t i = 0; i < count; i++) {
free(array[i]);
array[i] = NULL; // for safety
}
free(array);
*p = NULL;
}
// deal with the non portable conversion with macros
#define FREE_ARRAY(p, n) free_array((void ***)(void *)&(p), n)
// allocate an array of pointers to allocated things of size `size`.
// return a pointer to the array or `NULL` if any allocation failed
void **malloc_array(size_t count, size_t size) {
void **array = malloc(count * sizeof(*array));
if (array) {
for (size_t i = 0; i < count; i++) {
array[i] = calloc(size, 1); // allocate and initialize to all bits zero
if (array[i] == NULL) {
while (i-- > 0) {
free(array[i]);
array[i] = NULL;
}
return NULL;
}
}
}
return array;
}
#define MALLOC_ARRAY(n, type) ((type **)(void *)malloc_array(n, sizeof(type)))
#define MALLOC_2D_ARRAY(n1, n2, type) ((type **)(void *)malloc_array(n1, (n2) * sizeof(type)))
Passing the command as a string is very inefficient. You should use an int or an enum for the command, but you can use the above macros and code in your program this way:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint-gcc.h>
int main() {
int string_len = 100;
int num = 10; // get number from user;
char **my_arr = MALLOC_2D_ARRAY(num, string_len, char);
FREE_ARRAY(my_arr, num);
return 0;
}

Realloc array of Strings in C? segmentation error

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void sortString(const char* input, char* output);
int cmpstr(void const *a,void const *b);
int readAllWords(FILE* f, char*** res, int * num_read);
int main (int argc, char ** argv)
{
char **wordList;
FILE* fid;
int numWords;
fid = fopen(argv[1],"r");
readAllWords(fid, &wordList,&numWords);
}
int readAllWords(FILE* f, char*** res, int * num_read)
{
char buffer[128];
*num_read = 0;
int size;
while(fgets(buffer,128,f))
{
*num_read = *num_read +1;
size = strlen(buffer);
res = (char***)malloc(sizeof(char**));
*res = (char **)realloc(*res,sizeof(char*)*(*num_read));
(*res)[(*num_read)-1] = (char *)realloc((*res)[(*num_read)-1],sizeof(char)*size);
strcpy((*res)[(*num_read)-1],buffer);
printf("%s\n",(*res)[(*num_read)-1]);
}
printf("%s\n",(*res)[0]);
}
The values are storing and it prints out inside the while loop. But after the while loop, it cannot print out the strings.
The File is given in the main function. Do not understand why realloc is causing the loss of data?
One problem is that the code doesn't initialize res in main(), so you attempt to realloc() an indeterminate value. Either NULL or a value previously returned by malloc() or realloc() (or calloc()) would be OK, but since you pass an indeterminate value, you are invoking undefined behaviour, and a crash is a valid response to doing that.
However, there's a lot of other code in the function that should be reviewed as well.
This code works, and gets a clean bill of health from valgrind.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void readAllLines(FILE *f, char ***res, int *num_read);
int main(int argc, char **argv)
{
char **wordList = 0;
FILE *fid;
int numLines = 0;
if (argc > 1 && (fid = fopen(argv[1], "r")) != 0)
{
readAllLines(fid, &wordList, &numLines);
fclose(fid);
for (int i = 0; i < numLines; i++)
printf("%d: %s", i, wordList[i]);
for (int i = 0; i < numLines; i++)
free(wordList[i]);
free(wordList);
}
return 0;
}
void readAllLines(FILE *f, char ***res, int *num_read)
{
char buffer[128];
int size;
while (fgets(buffer, sizeof(buffer), f))
{
*num_read = *num_read + 1;
size = strlen(buffer) + 1;
char **space = (char **)realloc(*res, sizeof(char *) * (*num_read));
if (space == 0)
return;
*res = space;
(*res)[*num_read - 1] = (char *)malloc(sizeof(char) * size);
if ((*res)[*num_read - 1] == 0)
return;
strcpy((*res)[*num_read - 1], buffer);
printf("%s\n", (*res)[*num_read - 1]);
}
printf("%s\n", (*res)[0]);
}
Possible reason for a segmentation fault:
res = (char***)malloc(sizeof(char**));
*res = (char **)realloc(*res,sizeof(char*)*(*num_read));
In the second line you try to reallocate whatever *res is pointing to. However since you did not initialize *res this could be anything. This will work only if *res == NULL. I guess it should be malloc, not realloc.
Other problems:
You allocate everything new in each loop iteration. This is a huge memory leak.
You already pass a valid memory address pointing to an char** by res, you shouldn't allocate for it again. It is an out parameter. (Remove the malloc call)
You need an initial malloc for *res before the loop (Or set *res = NULL).
The second realloc for *res[...] should be a malloc, because you never actually reallocate here. Also instead of allocating size bytes, you should allocate size+1 bytes for the terminating \0.
Your function has no return statement although it is non-void.

Segfault in my csv_loader() function

I'm trying to write a csv parser in C, but every time I get a segfault in this function. I don't know how to fix it.
char*** csv_loader(char *filename){
FILE* file_xx;
file_xx = fopen(filename, "r");
if(file_xx==NULL){
printf("Failed to open File, no such file or directory!\n");
return 0;
}
int c_=0;
int **linenumbers;
int l=lines(filename);
linenumbers=malloc(sizeof(int)*l);
char*** loaded_csv;
int counter_line=0;
int counter_row=0;
loaded_csv=malloc(sizeof(char **) *l);
loaded_csv[0][0]=malloc(getfirstcolumn(filename)*sizeof(char)+2);
if(NULL==loaded_csv){
printf("Failed to initialize 'char** loaded_csv'!\n");
return 0;
}
int c_c=0;
int *cm=get_column_map(filename);
for(c_c=0;c_c<l;c_c++){
loaded_csv[c_c]=malloc(sizeof(char *)*cm[c_c]);
}
while(c_!=EOF){
c_=getc(file_xx);
if(c_=='\n'){
linenumbers[counter_line][cm[counter_line]]=counter_row+2;
loaded_csv[counter_line][cm[counter_line]]=malloc(counter_row*sizeof(char));
if(NULL == loaded_csv[counter_line][cm[counter_line]]){
return 0;
}
loaded_csv[counter_line][counter_row]='\0';
counter_row=0;
counter_line++;
}else{
if(c_==','){
counter_row=0;
}else{
counter_row++;
}
}
}
fclose(file_xx);
FILE*fgetsread;
fgetsread=fopen(filename, "r");
int ident, ident_c;
for(ident=0;ident<l;ident++){
for(ident_c=0;ident_c<cm[ident];ident_c++){
fgets(loaded_csv[ident][ident_c], linenumbers[ident][ident_c], fgetsread);
loaded_csv[ident][ident_c][linenumbers[ident][ident_c]-2]='\0';
}
}
fclose(fgetsread);
free(linenumbers);
return loaded_csv;
}
The Debugger says it's this line:
loaded_csv[0][0]=malloc(getfirstcolumn(filename)*sizeof(char)+2);
Does anyone know what's the bug? I'm yet new to C and anyway try to understand the malloc thing...
PS: the other functions are here: http://pastebin.com/VQZ4d5UU
So, you've allocated space on the line right before:
loaded_csv=malloc(sizeof(char **) *l);
That is fine and dandy, but loaded_csv[0] isn't yet initialized to somewhere you own. So, when you do the following line
loaded_csv[0][0]=malloc(getfirstcolumn(filename)*sizeof(char)+2);
you are trying to set a variable located in some random location (wherever loaded_csv[0] happens to be right then).
If you want to touch loaded_csv[0][0], you'll have to make sure that loaded_csv[0] is pointing to valid memory first (probably by allocating memory for it via malloc before you allocate something for loaded_csv[0][0].)
You've got a problem with this line:
loaded_csv[0][0]=malloc(getfirstcolumn(filename)*sizeof(char)+2);
Which suggest you are not allocating and initializing loaded_csv[0][0] right.
Here is an example of how to initialize and use a char ***var:
#include <windows.h>
#include <ansi_c.h>
char *** Create3D(int p, int c, int r);
int main(void)
{
char ***pppVar;
pppVar = Create3D(10,10,10);
//test pppVar;
strcpy(pppVar[0][0], "asdfasf");
strcpy(pppVar[0][1], "the ball");
return 0;
}
char *** Create3D(int p, int c, int r)
{
char *space;
char ***arr;
int x,y;
space = calloc (p*c*r*sizeof(char),sizeof(char));
arr = calloc(p * sizeof(char **), sizeof(char));
for(x = 0; x < p; x++)
{
arr[x] = calloc(c * sizeof(char *),sizeof(char));
for(y = 0; y < c; y++)
{
arr[x][y] = ((char *)space + (x*(c*r) + y*r));
}
}
return arr;
}
Be sure to keep track of and free(x) appropriately.

C reference gone after for loop

i got a problem with my C code.
int split(char* source, char*** target, char* splitChar) {
int i;
int currentLength;
int splitCharPosition;
char* currentSubstring = source;
int splitCount = charcount(source, splitChar) + 1;
*target = (char**) malloc(splitCount * sizeof(char**));
for(i=0;i<splitCount;i++) {
splitCharPosition = indexOf(currentSubstring, splitChar);
substring(currentSubstring, target[i], 0, splitCharPosition);
currentLength = strlen(currentSubstring);
substring(currentSubstring, &currentSubstring, splitCharPosition + 1, curr entLength-splitCharPosition);
}
return splitCount;
}
The problem is that if I use the Debugger, the pointer to splitChar is set to 0x0 after the first run of the for loop.
Does anybody know why it is set to 0x0?
EDIT:
int indexOf(char* source, char* template) {
int i;
int j;
int index;
for (i = 0; source[i]; i++) {
index = i;
for (j = 0; template[j]; j++) {
if (source[i + j] != template[j]) {
index = -1;
break;
}
}
if (index != -1) {
return index;
}
}
return -1;
}
EDIT2:
int charcount(char* source, const char* countChar) {
int i;
int count = 0;
for(i=0;source[i];i++) {
if(source[i] == countChar[0]) {
count++;
}
}
return count;
}
EDIT3:
char* substring(char* source, char** target, int start, int length) {
*target = (char*) malloc(length + 1);
strncpy(*target, source + start, length);
target[length] = '\0';
return *target;
}
EDIT4:
I just noticed that if I add
char* sndfpgjps = splitChar;
to my split() code it does not delete the reference. Anyone know why?
This line:-
substring(currentSubstring, &currentSubstring, splitCharPosition + 1, curr entLength-splitCharPosition);
... will cause a memory leak, as well as being incredibly inefficient. The old substring is left dangling. and never freed.
It would be much better to write
currentSubString += splitCharPosition + 1;
I don't think that's the problem, but it's a problem.
Also, as you're using C library functions like strlen(), why aren't you using strtok or better yet, strtok_r?
I have some reservations about the code, but this works cleanly under valgrind (no leaks, no abuse). I've left the sub-functions largely unchanged except that constant strings are marked constant. The code in split() has been simplified. As I noted in a comment, I suggest writing the main split() function so that you have a local char **string_list; which you allocate and fill. Then, when you're about to return, you assign *target = string_list;. This will make it easier for you to understand what's going on. Triple indirection is nasty. You can justify it here (just), but minimize the time you spend working with triple pointers. The revision adopts that strategy.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern int split(const char *source, char ***target, const char *splitStr);
static int
indexOf(const char *source, const char *template)
{
int i;
int j;
int index;
for (i = 0; source[i]; i++)
{
index = i;
for (j = 0; template[j]; j++)
{
if (source[i + j] != template[j])
{
index = -1;
break;
}
}
if (index != -1)
return index;
}
return -1;
}
static int
charcount(const char *source, const char *countChar)
{
int count = 0;
for (int i = 0; source[i]; i++)
{
if (source[i] == countChar[0])
count++;
}
return count;
}
static char *
substring(const char *source, int start, int length)
{
char *target = (char *)malloc(length + 1);
if (target != 0)
{
memmove(target, source + start, length);
target[length] = '\0';
}
return target;
}
int
split(const char *source, char ***target, const char *splitStr)
{
int splitCount = charcount(source, splitStr) + 1;
char **result = (char **)malloc(splitCount * sizeof(*result));
if (result == 0)
return -1;
int splitLength = strlen(splitStr);
char **next = result;
const char *currentSubstring = source;
for (int i = 0; i < splitCount; i++)
{
int splitCharPosition = indexOf(currentSubstring, splitStr);
if (splitCharPosition < 0)
break;
*next++ = substring(currentSubstring, 0, splitCharPosition);
currentSubstring += splitCharPosition + splitLength;
}
*next++ = substring(currentSubstring, 0, strlen(currentSubstring));
*target = result;
return (next - result); /* Actual number of strings */
}
static void print_list(int nstrings, char **strings)
{
for (int i = 0; i < nstrings; i++)
{
if (strings[i] != 0)
printf("%d: <<%s>>\n", i, strings[i]);
}
}
static void free_list(int nstrings, char **strings)
{
for (int i = 0; i < nstrings; i++)
free(strings[i]);
free(strings);
}
int main(void)
{
const char source[] = "This is a string; it is really!";
char **strings;
int nstrings;
nstrings = split(source, &strings, " ");
printf("Splitting: <<%s>> on <<%s>>\n", source, " ");
print_list(nstrings, strings);
free_list(nstrings, strings);
nstrings = split(source, &strings, "is");
printf("Splitting: <<%s>> on <<%s>>\n", source, "is");
print_list(nstrings, strings);
free_list(nstrings, strings);
return 0;
}
Note that in the second example, charcount() returns 6 but there are only 4 strings. This caused a late adjustment to the source code. (You could realloc() the result so it is exactly the right size, but it probably isn't worth worrying about unless the discrepancy is really marked — say 'more than 10 entries'.) The error handling is not perfect; it doesn't access invalid memory after failure to allocate, but it doesn't stop trying to allocate, either. Nor does it report failures to allocate individual strings — it does for failure to allocate the array of pointers.
I'd probably avoid the triple pointer by creating a structure:
typedef struct StringList
{
size_t nstrings;
char **strings;
} StringList;
You can then pass a pointer to one of these into split(), and into the utility functions such as free_list() and print_list(). The free_list() function would then modify the structure so that both elements are zeroed after the data pointed at by the structure is freed.
I'd also be tempted to use a different implementation of indexOf():
int indexOf(const char *haystack, const char *needle)
{
const char *pos = strstr(haystack, needle);
if (pos != 0)
return (pos - haystack);
return -1;
}
I do not know what substring does, nor what signature it has, but in the line
substring(currentSubstring, target[i], 0, splitCharPosition);
target[i] is only defined for i==0. I believe you wanted to write
substring(currentSubstring, (*target)[i], 0, splitCharPosition);
See if your debugger also supports data breakpoints, i.e. break if some place in memory is modified. Then place one at the actual address of splitChar, and another at the address it points to. (Since you didn't specify whether the pointer is null or points to nil.) See where it breaks. It may be that it is a completely unrelated place; that would indicate a buffer overflow.
Also, you could make at least splitChar a pointer to const. You don't actually want to modify it, right? Better idea, make it a char, not a pointer, since its name suggests that there is only one character on which you split, not a string.
The first call to substring does not look correct:
substring(currentSubstring, target[i], 0, splitCharPosition);
I suspect it should be something like the following where it indexes the actual memory that was allocated:
substring(currentSubstring, &((*target)[i]), 0, splitCharPosition);
You first need to get the value that target points at (*target) and then index off of that and pass the address of that array location.

Allocating and Freeing pointer to pointer

I'm attempting to pass a pointer to a pointer (char**) into a function that will initialize it, and then pass it into another function that will free the memory, however I'm getting seg faults on the freeing which leads me to believe my allocation is going wrong.
Valgrind is reporting use of uninitalized value at this line. tmp[i] is pointing to 0x0.
if(tmp[i]) free((char*)tmp[i]);
Here is the code (this is only test code)
void
alloc_strings(char ***test, int count)
{
char **tmp = *test;
tmp = malloc(count * sizeof(char*));
int i;
for(i = 0; i < count; i++) {
tmp[i] = malloc(6);
strcpy(tmp[i],"Hello");
}
}
void
free_strings(char ***test, int count)
{
char **tmp = *test;
int i;
for(i = 0; i < count; i++) {
if(tmp[i]) free((char*)tmp[i]);
}
if(tmp)
free(tmp);
}
And the invocation:
int
main(int argc, char **argv)
{
char **test;
alloc_strings(&test, 10);
free_strings(&test, 10);
return 0;
}
I have been playing around with this for a while, reading up on pointers etc however can't get my head around the issue. Any thoughts greatly appreciated!
You need to assign to *test, not to assign from it. How about:
void
alloc_strings(char ***test, int count)
{
char **tmp = malloc(count * sizeof *tmp);
/*...*/
*test = tmp;
}
In the code example,
alloc_strings(char ***test, int count)
{
char **tmp = *test;
*test should have some space to store a pointer to char ** which currently is not allocated. Hence, if the example is as this
char** array[1];
alloc_strings(&array[0], 7);
I feel that the code will work.

Resources