add_to_array call results in NULL list - c

I have a C struct that basically contains two 2D char arrays called List. One for appended items and another for inserted items. Then use external functions that add C strings to these arrays called add_to_array.
The problem I'm having is when I call add_to_array once it goes through without issues but once called a second time, I get a segmentation fault. With test code, I discovered for what ever reason that I can't figure out, the 2D array(s) in List remain NULL after calling add_to_array. I checked the result of add_to_array and it returns 1 (success) every time.
the target system/OS is Ubuntu linux.
typedef struct
{
char** appended;
char** inserted;
size_t app_alloc;
size_t app_elem;
size_t ins_alloc;
size_t ins_elem;
}
List;
void init_list(List* list)
{
list->app_alloc = 0;
list->ins_alloc = 0;
list->app_elem = 0;
list->ins_elem = 0;
list->appended = NULL;
list->inserted = NULL;
}
void free_list(List* list)
{
size_t i = 0;
for (; i < list->ins_elem; ++i)
{
free(list->inserted[i]);
}
free(list->inserted);
i = 0;
for (; i < list->app_elem; ++i)
{
free(list->appended[i]);
}
free(list->appended);
}
int add_to_array(const char* in, char** array, size_t* alloc, size_t* elem)
{
if (*alloc == *elem)
{
if (*alloc == 0) *alloc = list_buff;
else *alloc = (*alloc) * 2;
char** _tmp = (char**) realloc(array, (*alloc) * sizeof(char*));
if (!_tmp) return 0;
else array = _tmp;
}
array[(*elem)] = (char*) malloc(strlen(in) + 1);
strcpy(array[(*elem)], in);
(*elem)++;
return 1;
}
int append_list(const char* in, List* out)
{
return add_to_array(in, out->appended, &out->app_alloc, &out->app_elem);
}
int insert_list(const char* in, List* out)
{
return add_to_array(in, out->inserted, &out->ins_alloc, &out->ins_elem);
}
int main()
{
List test;
init_list(&test);
append_list("test", &test);
if (!test.appended)
{
printf("*%s*", "why is test.appended still NULL?");
}
//append_list("wwww", &test);
//insert_list("ffff", &test);
//printf("%s\n", get_element(0, &test));
//printf("%s\n", get_element(1, &test));
//printf("%s\n", get_element(2, &test));
//free_list(&test);
return 0;
}
Output: why is test.appended still NULL?
thanks to David's advice, I got my code working here's the changes:
int add_to_array(const char* in, char*** array, size_t* alloc, size_t* elem)
{
if (*alloc == *elem)
{
if (*alloc == 0) *alloc = list_buff;
else *alloc = (*alloc) * 2;
char** _tmp = (char**) realloc((*array), (*alloc) * sizeof(char*));
if (!_tmp) return 0;
else (*array) = _tmp;
}
(*array)[(*elem)] = (char*) malloc(strlen(in) + 1);
strcpy((*array)[(*elem)], in);
(*elem)++;
return 1;
}
int append_list(const char* in, List* out)
{
return add_to_array(in, &out->appended, &out->app_alloc, &out->app_elem);
}
int insert_list(const char* in, List* out)
{
return add_to_array(in, &out->inserted, &out->ins_alloc, &out->ins_elem);
}

Because C is a pass-by-value language :-)
You seem to be expecting that when you call:
add_to_array(in, out->appended, &out->app_alloc, &out->app_elem);
and then do
int add_to_array(const char* in, char** array, size_t* alloc, size_t* elem)
{
....
array = _tmp;
....
that the change to array will also change out->appended.
If you want it to work that way, you would have to pass a pointer to out->appended, and make add_to_array look like
int add_to_array(const char* in, char*** array, size_t* alloc, size_t* elem)

Related

Failing to assign memory to a pointer of a pointer

My problem is that it fails to assign memory to a (char*) pointer and I can't seem to understand why.
I reviewed other similar questions, but I can't seem to grasp the answer.
I'm trying to return a list of strings, but I know that in C I can't return char**, but I can do that via the char** parameter. My attempt is in the code snippets below.
in a.c
void list(char** fileList) {
int fileIndex = 0;
fileList = (char**)malloc(DIRECTORY_SIZE * sizeof(char*));
while ((dir = readdir(currentDirectory)) != NULL)
{
fileList[fileIndex] = (char*)malloc(FILENAME_LENGTH * sizeof(char)); //It fails here
fileList[fileIndex] = strncpy(fileList[fileIndex], dir->d_name, FILENAME_LENGTH);
fileIndex++;
printf("%s\n", fileList[fileIndex]);
}
}
in main.c
int main() {
char** fileList;
list(fileList);
for(int i = 0; i < 10; i++) {
printf("%s\n", fileList[i]);
}
}
I already looked over these questions:
Assigning memory to double pointer?
segment fault, assigning to double pointer in c
Assigning memory to double pointer?
What happens is that the memory pointer fileList gets copied to the list function, when the list function then changes the pointer, but the initial pointer wouldn't change.
To fix this you could give it a pointer to the pointer to change the actual pointer value, like this:
void list(char*** fileList) {
int fileIndex = 0;
*fileList = (char**)malloc(DIRECTORY_SIZE * sizeof(char*));
while ((dir = readdir(currentDirectory)) != NULL)
{
*fileList[fileIndex] = (char*)malloc(FILENAME_LENGTH * sizeof(char)); //It fails here
*fileList[fileIndex] = strncpy(fileList[fileIndex], dir->d_name, FILENAME_LENGTH);
fileIndex++;
printf("%s\n", fileList[fileIndex]);
}
}
int main() {
char** fileList;
list(&fileList);
for(int i = 0; i < 10; i++) {
printf("%s\n", fileList[i]);
}
}
But I personally find this a bit clunky, so it would be better to do it like this:
char** list(void) {
char** fileList;
int fileIndex = 0;
fileList = (char**)malloc(DIRECTORY_SIZE * sizeof(char*));
while ((dir = readdir(currentDirectory)) != NULL)
{
fileList[fileIndex] = (char*)malloc(FILENAME_LENGTH * sizeof(char)); //It fails here
fileList[fileIndex] = strncpy(fileList[fileIndex], dir->d_name, FILENAME_LENGTH);
fileIndex++;
printf("%s\n", fileList[fileIndex]);
}
return filelist;
}
int main() {
char** fileList = list();
for(int i = 0; i < 10; i++) {
printf("%s\n", fileList[i]);
}
}

Using an array of structures with call by reference

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

Return argument doesn't work — gives me weird error

This is a simple program that should create a substring from a string, then it should return the substring as something that can be printed out.
It's actually an exercise and only the substring function can be changed. The problem is that I can't find a return type that doesn't spark all kinds of warnings and errors.
How should I change the return type?
static void panic(const char *serror)
{
printf("%s", serror);
exit(1);
}
static void *xmalloc(size_t size)
{
void *ptr;
if (size == 0)
panic("Size is 0!\n");
ptr = malloc(size);
if (!ptr)
panic("No mem left!\n");
return ptr;
}
static char *substring(const char *str, off_t pos, size_t len)
{
char out [len];
int index;
for(index = 0; index < (pos + len); index++)
{
if(index >= pos && index < (pos + len))
{
out[index - pos] = str[index];
}
}
return out;
}
int main(int argc, char **argv)
{
char *foo = "Nicht\n";
char *bar = substring(foo, 2, 3);
printf("%s", bar);
free(bar);
return 0;
}
You invoked two undefine behavior by
dereferencing a pointer bar that points at already vanished local variable.
passing a non-NULL pointer which doesn't point at buffer allocated via malloc(), calloc() or realloc().
Also note that
You have to terminate the string by adding null character.
Your loop is not efficient.
corrected code:
static char *substring(const char *str, off_t pos, size_t len)
{
char *out = xmalloc(len + 1);
int index;
for(index = pos; index < (pos + len); index++)
{
out[index - pos] = str[index];
}
out[len] = '\0';
return out;
}

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.

How to malloc inside a function and return pointer in C?

Below is some psudo, but I'm trying to accomplish this. The problem is as written, it returns a blank pointer.
int testFunction(char *t) {
int size = 100;
t = malloc(100 + 1);
t = <do a bunch of stuff to assign a value>;
return size;
}
int runIt() {
char *str = 0;
int str_size = 0;
str_size = testFunction(str);
<at this point, str is blank and unmodified, what's wrong?>
free(str);
return 0;
}
This works fine if I have a predefined size, such as char str[100] = "" and I don't try to malloc or free memory afterwords. I need to be able to make the size dynamic though.
I've also tried this, but seem to run into a corrupt pointer somehow.
int testFunction(char **t) {
int size = 100;
t = malloc(100 + 1);
t = <do a bunch of stuff to assign a value>;
return size;
}
int runIt() {
char *str = 0;
int str_size = 0;
str_size = testFunction(&str);
<at this point, str is blank and unmodified, what's wrong?>
free(str);
return 0;
}
Thanks!
Your test function is just a bit backward. Size should be an input. The allocated pointer should be the output:
char* testFunction(int size) {
char* p = malloc(size);
<do a bunch of stuff to assign a value>;
return p;
}
int runIt() {
char *str = 0;
int str_size = 100;
str = testFunction(str_size);
<do something>
free(str);
return 0;
}
edit
Per comment, making size an output too.
char* testFunction(int *size) {
*size = <compute size>;
char* p = malloc(size);
<do a bunch of stuff to assign a value>;
return p;
}
int runIt() {
char *str = 0;
int str_size;
str = testFunction(&str_size);
<do something>
free(str);
return 0;
}
You're nearly there with the second example, but change
int testFunction(char **t) {
...
t = malloc(100 + 1);
To
int testFunction(char **t) {
...
*t = malloc(100 + 1);
The point being that you're passing in a char**, a pointer to a pointer, so you want to assign the malloc to what that points at (a pointer).
I am also studying c++. I had a the same question. So after speaking to c++ pro at work, he suggest me to do something like this
int method(char* p) {
if (p) {
strcpy(p, "I like c++");
}
return strlen("I like c++");
}
int main()
{
char* par = NULL;
int len = method(par);
if (len > 0) {
par = (char*)malloc(len+1);
memset(par, 0, len + 1);
method(par);
cout << "ret : " << par;
}
free(par);
}

Resources