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;
}
**
Related
I am trying to make a simple example of a array that increases with its input. The input is a series of numbers and the end of this series is a zero. What I thought of was to increase my array every time a new number is read, but for some reason this does not seem to work since I get an error:
Realloc(): invalid pointer
This is my current code:
#include <stdio.h>
#include <stdlib.h>
int *resizeIntArray(int *series, int newSize) {
int *newSeries = realloc(series, newSize * sizeof(int));
if (newSeries == NULL) {
printf("Error: Memory allocation failed");
exit(-1);
}
return newSeries;
}
int main(int argc, char *argv[]) {
int number;
scanf("%d", &number);
int *numbers;
int size = 0;
while (number != 0) {
numbers = resizeIntArray(numbers, size + 1);
printf("%d ", number);
scanf("%d", &number);
size++;
}
}
You are passing an uninitialised variable to your function, in turn passed to realloc, which needs either a pointer to previously allocated memory, or NULL.
So initialise that variable:
int *numbers = NULL;
There are multiple issues in your code:
you do not initialize numbers to NULL, so realloc() invokes undefined behavior the first time it is called. This is causing the problem you observe.
you do not check the return value of scanf(), causing a potential endless loop and undefined behavior if the input stream does not contain a 0 number.
you do not store the number in the reallocated array...
you do not free the array (minor).
you do not return 0 at the end of main() (minor).
Here a simpler and safer version:
#include <stdio.h>
#include <stdlib.h>
int *resizeIntArray(int *series, int newSize) {
int *newSeries = realloc(series, newSize * sizeof(int));
if (newSeries == NULL) {
printf("Error: Memory allocation failed");
exit(-1);
}
return newSeries;
}
int main(int argc, char *argv[]) {
int number;
int *numbers = NULL;
int i, size = 0;
/* reading the numbers */
while (scanf("%d", &number) == 1 && number != 0) {
numbers = resizeIntArray(numbers, size + 1);
numbers[size++] = number;
}
/* printing the numbers */
for (i = 0; i < size; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
free(numbers);
return 0;
}
You can try an approach like this. This includes:
Memory checking, with appropriate error messages.
use of malloc() and realloc() to allocate and reallocate memory.
Allocates sufficient space when needed on run-time.
Appropriately checks return value of scanf().
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#define EXIT 0
void exit_if_null(void *ptr, const char *msg);
int
main(int argc, char const *argv[]) {
int *numbers = NULL;
int number, num_size = 1, count = 0, i;
/* initial allocation of memory */
numbers = malloc(num_size * sizeof(*numbers));
/* small error checking, to be safe */
exit_if_null(numbers, "Initial Allocation");
/* Reading in numbers */
printf("Enter numbers(0 to end): ");
while (scanf("%d", &number) == 1 && number != EXIT) {
/* valid number found, but is there space? */
if (num_size == count) {
num_size *= 2;
/* resize run-time array */
numbers = realloc(numbers, num_size * sizeof(*numbers));
exit_if_null(numbers, "Reallocation");
}
numbers[count++] = number;
}
/* print out numbers */
printf("Your numbers stored in array:\n");
for (i = 0; i < count; i++) {
printf("%d ", numbers[i]);
}
/* free allocated memory, very important */
free(numbers);
return 0;
}
/* helper function for error checking */
void
exit_if_null(void *ptr, const char *msg) {
if (!ptr) {
printf("Unexpected null pointer: %s\n", msg);
exit(EXIT_FAILURE);
}
}
First you should first allocate some memory before reallocate it. So your code will change as:
#include <stdio.h>
#include <stdlib.h>
int *resizeIntArray(int *series, int newSize){
int *newSeries = realloc(series,newSize*sizeof(int));
if(newSeries == NULL){
printf("Error: Memory allocation failed");
exit(-1);
}
return newSeries;
}
int main(int argc, char* argv[]) {
int number;
scanf("%d",&number);
int *numbers=malloc(sizeof(int));///CHANGED
int size = 1;///CHANGED
while(number != 0){
numbers = resizeIntArray(numbers,size +1);
printf("%d ",number);
scanf("%d",&number);
size++;
}
}
But white you are doing is quite not efficent. A realloc() function hides a free() a malloc() and the worst one: memcpy(). So if you realloc() at each new item, you are going to have a bad time... O(n^2) exactly.
the best way to do it is to allocate a buffer of memory:
struct vector
{
int *numbers;
size_t size;
size_t i;
}
#define DEFAULTBUF 100
int main()
{
struct vector v;
v.numbers=malloc(sizeof(int)*DEFAULTBUF);
v.size=DEFAULTBUF;
v.i=0;
scanf("%d",&number);
while(number != 0 && v.numbers){
if (v.i->=v.size)
{ v.size+=v.size
v.numbers=realloc(v.numbers,sizeof(int)*v.size);
///i leave to you the error handling
}
v.i++;
printf("%d ",number);
scanf("%d",&number);
}
}
The correct use of realloc() malloc() and similar is very important. And also the increasing ratio of the resize. For the datastructure I ever double it. For text I proceed linearly
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;
}
i have a problem with the initialization of the values inside the first dynamic array of pointers
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char*** GetIndexes()
{
int n = 0;
char ***index;
printf("please insert the number of words you want to add to dictionary\n");
scanf("%d", &n);
index = (char***)calloc(n, sizeof(char));
if (index == NULL)
{
printf("allocation Failed");
return;
}
return index;
}
char** GetDefinitions()
{
int n = 0;
char **definition;
printf("please insert the number of defintions you want to add to the word\n");
scanf("%d", &n);
definition = (char**)calloc(n+1, sizeof(char));
if (definition == NULL)
{
printf("allocation failed");
return;
}
return definition;
}
int main()
{
char *** dptr = GetIndexes();
if (dptr == NULL)
{
printf("memory Allocation failed");
}
int indexcount = sizeof(dptr) / sizeof(char),i;
for (i = 0; i < indexcount; i++)
{
printf("word number %d\n", i + 1);
*dptr[i] = GetDefinitions();
}
printf("%p",dptr);
}
i tried running the debugger in VS2013 and after i enter the number of defintions i want it crashed with this message:
Unhandled exception at 0x01103FB0 in ConsoleApplication1.exe: 0xC0000005: Access violation writing location 0x00000000.
i missed an allocation of something but i cant quite figure out what i missed,
thanks in advance
Your program is very broken
You allocate n char ***s but only request space for n chars and also do it for char **, to prevent this kind of mistake you may use the sizeof operator this way
char ***index;
index = calloc(n, sizeof(*index));
and
char **definition;
definition = calloc(n, sizeof(*definition));
and as you see casting calloc makes it harder and it's not necessary.
You have a return statement that doesn't return anything an GetIndexes() as well as one in GetDefinitions.
They should return NULL if you want to handle failure in the caller function
return NULL;
You erroneously use the sizeof operator to determine the number of char *** pointer allocated in
int indexcount = sizeof(dptr) / sizeof(char)
this will be either 4 or 8 depending on the architecture i.e. the size of a pointer divided by 1 sizeof(char) == 1 always.
You can't compute that value, you simply have to keep track of it. The size
You dereference the triple pointer twice and try to assign a double pointer to it
*dptr[i] = GetDefinitions();
here the operator precedence is also an issue, but regardless of that, this is wrong, may be what you meant was
dptr[i] = GetDefinitions();
This is not going to make your program crash, but it's certainly important to free all malloced pointers before exiting the program.
Here is a suggestion for your code to work, ignore it's purpose since it's not clear what you are trying to do
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char ***GetIndexes(unsigned int *count)
{
char ***index;
printf("please insert the number of words you want to add to dictionary > ");
scanf("%u", count);
index = calloc(*count, sizeof(*index));
if (index == NULL)
{
printf("allocation Failed");
return NULL;
}
return index;
}
char **GetDefinitions(unsigned int *count)
{
char **definition;
printf("please insert the number of defintions you want to add to the word > ");
scanf("%u", count);
definition = calloc(*count + 1, sizeof(*definition));
if (definition == NULL)
{
printf("allocation failed");
return NULL;
}
return definition;
}
int main()
{
unsigned int indexCount, i;
char ***dptr = GetIndexes(&indexCount);
if (dptr == NULL)
{
printf("memory Allocation failed");
}
for (i = 0; i < indexCount; i++)
{
unsigned int definitionsCount;
printf("Word number %u\n", i + 1);
dptr[i] = GetDefinitions(&definitionsCount);
if (dptr[i] != NULL)
{
/* use dptr[i] here or maybe somewhere else, but when you finish */
free(dptr[i]);
}
}
printf("%p", dptr);
/* now if you are done using dptr */
free(dptr);
return 0;
}
As already mentioned in the comment this is a very bad idea and just using double pointers is good here. But the below fixes should be done if you want to use pointers to allocate memory
index = calloc(n, sizeof(char));
should be
index = calloc(n, sizeof(char **));
and
definition = calloc(n+1, sizeof(char));
should be
definition = calloc(n+1, sizeof(char *));
I am learning pointer in c
i have written a small program , but i am getting segmentaion fault
i dont know where i am having the issue
please let me know the issue with the code , it is an array of pointers to string ,
which is in a pointer to structure .
# include <stdio.h>
#include <stdlib.h>
# include <string.h>
char *sum(char **sol) ;
char *summer_sum(char*** solcs) ;
int main()
{
char* datum ="teststring";
sum(&datum);
}
char *sum(char** sol)
{
printf("\n value is : %s",*sol);
summer_sum(&sol);
return "1" ;
}
char *summer_sum(char*** solcs)
{
int i=0;
typedef struct
{
char *asg[40];
}nlist;
nlist *n1;
for( i=0 ; i<= 38 ;i++)
{
n1->asg[i] = calloc(1,1*sizeof(*solcs));
strcpy(n1->asg[i],**solcs);
printf("\n %d value is : %s",i,n1->asg[i]);
}
return NULL;
}
n1 is used uninitialized:
n1->asg[i] = calloc(1,1*sizeof(*solcs));
On the other hand, if you want to allocate enough space for the use of strcpy, you must use strlen instead of sizeof
And you don't need a double or triple pointer, your code simplified:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void sum(char *sol);
char *summer_sum(char *solcs);
int main(void)
{
char *datum = "teststring";
sum(datum);
}
void sum(char *sol)
{
printf("\n value is : %s", sol);
summer_sum(sol);
}
char *summer_sum(char *solcs)
{
int i = 0;
size_t len;
typedef struct {
char *asg[40];
} nlist;
nlist *n1 = malloc(sizeof(*n1));
if (n1 == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
len = strlen(solcs); /* No need to compute len on each iteration */
for (i = 0; i <= 38; i++) { /* you are filling 39 and declared 40 */
n1->asg[i] = calloc(1, len);
/* Always check the result of (m/c/re)alloc */
if (n1->asg[i] == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
strcpy(n1->asg[i], solcs);
printf("\n %d value is : %s", i, n1->asg[i]);
/* Don't forget to free */
free(n1->asg[i]);
}
free(n1);
return NULL;
}
Before using n1->... You will have allocate memory to n1 as well using calloc()
There are two problems which involves dynamic memory allocation in your code:
n1 is not initialized, you should add a statement like n1 = malloc(sizeof(*n1)); before the for statement in summer_sum()
you did not allocate enough space for each asg[i], you should allocate spaces for these asg[i] by n1->asg[i] = malloc(strlen(**solcs) + 1);
You are using your pointer n1 uninitialized. Your program invokes undefined behavior. In such case you may get either expected or unexpected result.
Second, you are missing a closing brace } in function summer_sum.
My program compiles but I am not working with pointers and realloc correctly. I have tried looking at other examples but I can't seem to translate it to my own program. The point of the program is to read in words from a file and increment the count if they appear more than once. Once the array of structs goes over my base (5), I want to realloc space, copy the array over and then add the next word.
Any help would be greatly appreciated!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BASE 5
#define MAX 50
typedef char *string;
struct wordCount
{
string word;
unsigned int count;
};
int main (void)
{
unsigned int i;
unsigned int incremented;
unsigned int j;
char temp [40];
struct wordCount wordArray[BASE];
struct wordCount *holder;
FILE *infile;
j = 0;
infile = fopen("input.txt","r");
while (fscanf(infile, "%s", temp) == 1) {
incremented = 0;
for (i = 0; i < j; i++){
if(strcmp(temp,wordArray[i].word) == 0){
wordArray[i].count++;
incremented++;
}
}
if (incremented == 0){
if (j<BASE){
wordArray[j].word = (char *)malloc((strlen(temp)+1) *
sizeof(char));
strcpy(wordArray[j].word,temp);
wordArray[j].count = 1;
j++;
} else {
holder = realloc(wordArray, sizeof(wordArray) +1);
*wordArray = *holder;
wordArray[j].word = (char *)malloc((strlen(temp)+1) * sizeof(char));
strcpy(wordArray[j].word,temp);
wordArray[j].count = 1;
j++;
}
}
}
fclose(infile);
/* bring in next file*/
/*delete du plicates */
/*sort*/
for (i = 0; i < j; i++) {
printf("%s ", wordArray[i].word);
printf("%d\n", wordArray[i].count);
}
/* and when done:*/
for(i = 0; i < j; i++){
free(wordArray[i].word);
}
return 0;
}
Here's the most obvious place you're going wrong:
holder = realloc(wordArray, sizeof(wordArray) +1);
Note this line from the man page of realloc():
void *realloc(void *ptr, size_t size);
...
Unless ptr is NULL, it must have been returned by an earlier call to malloc(), calloc() or realloc().
Your wordArray is a statically allocated array, it was not dynamically allocated via malloc() or friends.