Why do I get the segmentation fault message at run time? (2-dimensional array of struct) [duplicate] - c

I was playing with double pointers in C and was wondering if I create a function that initializes the table, it crashes on going back to main when I try to make use of the memory allocated by InitStringTable. I believe a simple fix is to make strTable global and then I believe its OK, but I prefer not to do so as this is more of a learning exercise for me in passing the table around for modification i.e. I should be able to modify strTable from main or another function modifyTable after InitStringTable.
Thanks for any help you can give.
int main()
{
char** strTable;
// Allocates memory for string table.
InitStringTable(strTable);
// Below lines should be able to copy strings into newly allocated table.
// Below lines cause crash however.
strcpy(strTable[0], "abcdef");
strcpy(strTable[1], "xy");
}
// Allocates memory for the string table. This function should create a table
// of size 10 strings with each string 50 chars long. The code compiles fine.
void InitStringTable(char** table)
{
int i = 0;
table = (char**)malloc(sizeof(char)*10);
for(i = 0; i < 10; i++)
{
table[i] = (char*)malloc(sizeof(char)*50);
}
for(i = 0; i < 10; i++)
{
memset(table[i], 0, 50);
}
strcpy(table[0], "string1");
}

C is pass by value.
The value assigned to table is lost on returning from InitStringTable().
Also when allocating pointers to char ask for room for pointers to char.
So this:
... = (char**)malloc(sizeof(char)*10);
shall at least be (assuming C):
... = malloc(sizeof(char*)*10);
A possible approach to this would be:
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int InitStringTable(char *** ppptable, const size_t n, const size_t l)
{
int result = 0;
if (NULL == ppptable)
{
result = -1;
errno = EINVAL;
}
else
{
(*ppptable) = malloc(n * sizeof(**ppptable));
if (NULL == (*ppptable))
{
result = -1;
}
else
{
size_t i = 0;
for(; i < n; ++i)
{
(*ppptable)[i] = calloc(l, sizeof(*(*ppptable)[i]));
if (NULL == (*ppptable)[i])
{
result = -1;
/* Failing in the middle requires clean-up. */
for (; i > 0; --i)
{
free((*ppptable)[i-1]);
}
free(*ppptable);
(*ppptable) = NULL;
break;
}
}
}
}
return result;
}
Call it like this:
#include <stdlib.h>
#include <stdio.h>
int InitStringTable(char *** ppptable, const size_t n, const size_t l);
int main(void)
{
int result = EXIT_SUCCESS;
char ** strTable = NULL;
if ( -1 == InitStringTable(&strTable, 10, 42)) //* Allocate array with 10 "strings" à 42 chars. */
{
perror("InitStringTable() failed");
result = EXIT_FAILURE;
}
else
{
strcpy(strTable[0], "abcdef");
strcpy(strTable[1], "xy");
}
return result;
}
And no, I won't get into this ridiculous "You don't wanna be a 3-star-programmer!" discussion.

You have a pointer issue.
It's like if you say:
void inc(int a){
a++;
}
int main(){
int a = 0;
inc(a);
printf ("%d\n", a); // will display 0, not 1
}
does not work.
You must pass &strTable instead of strTable as InitStringTable argument, and change other things in InitStringTable consequently ..
Or just do strTable = InitStringTable(); , and return a char** from InitStringTable.

The lines below InitStringTable() crash, because they are trying to perform operations
on a memory address that is neither in the same scope as theirs nor have any reference to
that memory address.
The function InitStringTable() allocates memory to the table, but cannot be accessed by the
calling function (here main), because the memory is local to the function in which it
allocated.
Therefore in order to use the same memory address for operations in the
calling function you must pass a reference of that address to the calling function.
In your program you can do it as under :
Declare the function as :-
char **InitStringTable(char **);
int main()
{
char** strTable;
strTable = InitStringTable(strTable);
strcpy(strTable[0], "abcdef");
strcpy(strTable[1], "xy");
}
char **InitStringTable(char** table)
{
int i = 0;
table = (char**)malloc(sizeof(char)*10);
for(i = 0; i < 10; i++)
{
table[i] = (char*)malloc(sizeof(char)*50);
}
for(i = 0; i < 10; i++)
{
memset(table[i], 0, 50);
}
strcpy(table[0], "string1");
/* after the function has finished its job, return the address of the table */
return table;
}

Related

Memory allocation for char pointer in a struct

I'm trying to teach C to myself and I'm struggling with what it looks like a very basic thing. I have a struct with a char pointer and I want to dynamically allocate memory and free it once done. What I understand is that I need to allocate memory for both the struct and the char pointer but it looks like I'm missing something because I'm getting a Segmentation fault on the sprintf line.
As an exercise to understand and use malloc and free, I'm trying to build an easy program that takes an int as input and outputs a table with the factorials of all the numbers from 0 to input. Each table entry has its index (int), the result of the factorial (long long int) and the result but in an array of chars format (this is the problematic one).
Here's what I have until now:
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#define LIMIT 20
struct entry
{ /* Definition of each table entry */
int n;
long long int lli;
char *str;
};
void shout(char *m)
{
fprintf (stderr, "%s\n", m);
exit (0);
}
int main (int argc, char *argv[])
{
int n;
int i;
struct entry *fact_table;
if (argc != 2)
shout("wrong parameters");
n = atoi (argv[1]);
if (n < 0)
shout("n too small");
if (n > LIMIT)
shout("n too big");
// Allocate memory for struct
fact_table = (struct entry*) malloc((n+1) * sizeof(struct entry));
if (fact_table == NULL) {
shout("malloc");
}
// Compute factorials
fact_table[0].n = 0;
fact_table[0].lli = fact_table[1].n = fact_table[1].lli = 1; // 0! = 1! = 1
fact_table[0].str = fact_table[1].str = "1";
for (i=2; i<=n; i++) {
fact_table[i].n = i;
fact_table[i].lli = i * fact_table[i-1].lli; // N! = N*(N-1)!
int digits = log10(fact_table[i].lli) + 1; // get number of digits of the result to allocate memory in consequence
fact_table[i].str = malloc((digits + 1)*sizeof(char));
if (fact_table[i].str = NULL) {
shout("malloc");
}
sprintf(fact_table[i].str, "%lld", fact_table[i].lli); // convert to string. ERROR HERE
}
// print factorial table
for (i= 0; i<=n; i++)
{
printf ("%d %lld %s\n", fact_table[i].n, fact_table[i].lli, fact_table[i].str);
}
// Free memory
for (i=0; i<=n; i++) {
free(fact_table[i].str);
}
free(fact_table);
return 0;
}
I'm probably missing something very obvious and making a silly mistake when allocating the memory for the fact_table[i].str, but I'm struggling to make it work.
In addition to the comments about freeing the memory for n >= 2, if you look at your test after the malloc:
if (fact_table[i].str = NULL) {
You are setting your pointer to NULL. Instead you should write:
fact_table[i].str = malloc((digits + 1)*sizeof(char));
if ( fact_table[i].str == NULL) {
shout("malloc");
}
Just some little recommendation here. This mistake generates a warning on most compiler if you compile using -Wall:
fact.c: In function ‘main’:
fact.c:53:9: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
if (fact_table[i].str = NULL) {
^~~~~~~~~~
Also, in order to make sure the compiler will complain if you forget a =, you can compare the values of a variable and of a constant placing the constant on the left: if you write if (NULL = fact_table[i].str), your compiler will complain and notify you with the error.
I reproduced this issue on my setup. We need to fix two issues before program runs ok.
change 'fact_table[i].str = NULL' to 'fact_table[i].str == NULL'. Your previous command directly set 'str' to NULL, which is not expected. This is the reason you met segment error.
In Free memory part, you need to start from index 2. You cannot free memory which doesnot belong to you.
Below code can work well in my setup.
Wish this can help you.
**
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#define LIMIT 20
struct entry
{ /* Definition of each table entry */
int n;
long long int lli;
char *str;
};
void shout(char *m)
{
fprintf (stderr, "%s\n", m);
exit (0);
}
int main (int argc, char *argv[])
{
int n;
int i;
struct entry *fact_table;
if (argc != 2)
shout("wrong parameters");
n = atoi (argv[1]);
if (n < 0)
shout("n too small");
if (n > LIMIT)
shout("n too big");
// Allocate memory for struct
fact_table = (struct entry*) malloc((n+1) * sizeof(struct entry));
if (fact_table == NULL) {
shout("malloc");
}
// Compute factorials
fact_table[0].n = 0;
fact_table[0].lli = fact_table[1].n = fact_table[1].lli = 1; // 0! = 1! = 1
fact_table[0].str = fact_table[1].str = "1";
for (i=2; i<=n; i++) {
fact_table[i].n = i;
fact_table[i].lli = i * fact_table[i-1].lli; // N! = N*(N-1)!
int digits = log10(fact_table[i].lli) + 1; // get number of digits of the result to allocate memory in consequence
fact_table[i].str = malloc((digits + 1)*sizeof(char));
if (fact_table[i].str == NULL) {
shout("malloc");
}
sprintf(fact_table[i].str, "%lld", fact_table[i].lli); // convert to string. ERROR HERE
}
// print factorial table
for (i= 0; i<=n; i++)
{
printf ("%d %lld %s\n", fact_table[i].n, fact_table[i].lli, fact_table[i].str);
}
// Free memory
for (i=2; i<=n; i++) {
free(fact_table[i].str);
}
free(fact_table);
return 0;
}
**

Why can't I Iterate over a string that is returned in C?

When I iterate through a string in a void function like this it doesn't give me any problem and iterates through the string I input.
#include <stdio.h>
#include <string.h>
void iter_string (void){
char source[30];
scanf(" %[^\n]s",source );;
int length = (int)strlen(source); //sizeof(source)=sizeof(char *) = 4 on a 32 bit implementation
for (int i = 0; i < length; i++)
{
printf("%c\n", source[i]);
}
//return 0;
}
int main(void)
{
iter_string();
return 0;
}
However, problems arise when I modify the function to return the input value and store it in a value in the main function. It gives me an error called segmentation fault:11. Why is this?
const char* iter_string (void){
char source[30];
scanf(" %[^\n]s",source );;
int length = (int)strlen(source); //sizeof(source)=sizeof(char *) = 4 on a 32 bit implementation
for (int i = 0; i < length; i++)
{
printf("%c\n", source[i]);
}
return *source;
}
int main(void)
{
char author[30];
strcpy(author,iter_string());
printf("%s\n",author );
return 0;
}
Because you are returning a reference to a memory that no longer exists once the function finishes executing.
You have to declare it dinamically if you want to return that pointer:
char *source = malloc(30);
// Do your processing here...
return source; // No asterisk here
Then in main, to do a proper cleaning on the memory allocated inside the function you should free the stuff you malloc'ed:
char * temp = iter_string();
strcpy(author, temp);
free(temp);
Other alternativa would be to pass author as parameter and alter it inside.

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

Retaining memory allocated in function body

In one of the programs, I created a function whose one argument was a pointer. The function dynamically allocated some memory to the pointer and returned the size of allocated memory along with other details. But, the allocated memory is destroyed as soon as the function is executed.
How can I retain access and data integrity outside the function to the memory allocated inside the function?
Here's the code modified after reading the replies:
void initialize(int **arr)
{
int i = 0;
*arr = malloc(sizeof(int) * 10);
for (; i < 10; ++i)
*arr[i] = i + 1;
for (i = 0; i < 10; ++i)
printf("\n%d", *arr[i]);
}
int main()
{
int i = 0;
int *arr;
initialize(&arr);
for (; i < 10; ++i)
printf("\n%d", arr[i]);
return 0;
}
But when I run it, it says "rr.exe has stopped working"; although it compiles successfully. Nothing gets printed, not even from the printf in the the function.
Do not call free() on the pointer received by the dynamical allocation, but return it from the function to the calling process.
Example:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
/* give_me_memory(void ** ppv, size_t n) allocates n bytes to *ppv. */
/* The function returns 0 on success or -1 on error. On error errno is set accordingly. */
int give_me_memory(void ** ppv, size_t n)
{
if (NULL == ppv)
{
errno = EINVAL; /* Bad input detected. */
return -1;
}
*ppv = malloc(n);
if (NULL == *ppv)
{
return -1; /* malloc() failed. */
}
return 0; /* Getting here mean: success */
}
int main(void)
{
void * pv = NULL;
if (-1 == give_me_memory(&pv, 42))
{
perror("give_me_memory() failed");
return 1;
}
/* Do something with the 42 bytes of memory. */
free(pv);
return 0;
}
I guess your function looks like:
void f(int *pointer)
{
pointer = (int*)malloc(sizeof(int));
}
this is bad because, your function gets a copy of pointer. Imagine your function takes int as argument and changes its value. Original variable passed to function won't changed, because you passed it as a copy. Here We have the same - you can modify what's poitner pointing at, but not pointer itself.
What do we do when we want to pass variable to function so it can be changed inside? We pass it as a pointer. here You need to do the same - pass pointer to pointer:
void f(int **pointer)
{
*pointer = (int*)malloc(sizeof(int));
}
and call it like this:
int *p = 0;
f(&p);

memory leak for simple program, how can I free allocs?

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

Resources