I started working on a program and I need to create function, that reads input, in format {number,number, ...} and puts numbers into dynamically allocated array. I am currently having trouble reallocating the array. Here is the code. The program compiles with no errors or warnings
int readInput(int ** znamky, int *count )
{
size_t n = 1;
char overeni[2];
char znaminko[2];
char carka [2] = ",";
char zavorka[2] ="{";
char zavorka2[2] ="}";
printf("Pocty bodu:\n");
scanf(" %c",&overeni[0]); // I check if first character is {
if (overeni[0]!=zavorka[0])
{
printf("Nespravny vstup.\n");
return EXIT_FAILURE;
}
while (scanf("%d",znamky[*count])==1) // here I enter the cycle and load first number
{
if (scanf(" %c",&znaminko[0])==1) // if char after number is ","
{
if (znaminko[0]==carka[0])
{
printf("sdf\n");
*count = *count + 1; // I append lenght of array
if (*count==n) // if the length is same as currently allocated memory
{
n = n*2;
*znamky = (int*) realloc (*znamky, n * sizeof(int) + 4);
// Here I am trying to reallocate the memory and when using debugger it probably goes ok, but //the problem is when I repeat the cycle for the second time because I get seg fault
}
continue;
}
if (znaminko[0]==zavorka2[0])
{
*count = *count + 1;
printf("utikam\n");
return 1;
}
}
else
{
printf("Nespravny vstup\n");
return EXIT_FAILURE;
}
}
return 1;
}
int main (void)
{
int *znamky = (int*) malloc (sizeof(int));
int count = 0;
if (znamky == NULL)
{
free (znamky);
return EXIT_FAILURE;
}
readInput(&znamky, &count);
return 0;
}
So I was wondering if someone could explain to me what is happening inside the program, I still feel a little bit lost with pointers, and passing arrays to functions.
Thank you very much...
Related
I am trying to write a program that reads input and prints it with 60 characters each line, with a pointer to store the characters.
And I always get segmentation fault when entering a lot of characters, and I think the realloc() cause it but I can't figure out why.
This is my code (a little long but if someone can help me I will be thankful):
Ignore the empty functions.
int main() {
int opt;
char *p;
int checkRead = -1;
p = (char*) calloc(60,1);
scanf("%d",&opt);
checkRead = readText(opt,p);
if (!checkRead) {
}
int readText(int opt, char *p) {
switch(opt) {
case dynamicList:
return dynamicReadText(p);
return 1;
}
int dynamicReadText(char *p) {
register int i;
int ch;
char *checker = NULL;
fflush(stdin);
for (i = 0; (ch = getchar()) != EOF; i++) {
if (i >= 60 && i % 60 == 0) {
checker = (char*)realloc(p,i+60);
if (!*(checker)) {
return 0;
}
p = checker;
free(checker);
checker = NULL;
*(p+i) = '\n';
i++;
}
if (ch == '\n') {
i--;
}
else {
*(p+i) = ch;
}
}
*(p+i) = '\0';
return 1;
}
The problems are numerous.
checker = (char*)realloc(p,i+60);
if (!*(checker))
should be
checker = (char*)realloc(p,i+60);
if (!checker)
You want to check if the value returned by realloc is NULL. You are instead checking if the first character of the memory block is zero.
This second problem is the probably the one leading to the SIGSEGV.
Select lines of your code:
char *checker = NULL;
checker = (char*)realloc(p,i+60); // Allocates a memory block.
p = checker; // Both p and checker points to this block.
free(checker); // The block is freed.
*(p+i) = '\n'; // XXX Derefs a pointer pointing to freed memory.
Finally, you are changing the dynamicReadText's p with the expectancy that this will change the p in readText. Similarly, you expect that changing readText's p will change main's. But these are entirely different variables. C always passes by value.
Well, I said finally, but only in the sense that this is the extent of what this answer covers. I haven't established that there are no other problems.
All together, your code should look something like this:
int f(char **p_ptr) {
...
while (...) {
...
char* tmp = realloc(*p_ptr, ...);
if (!tmp) {
...
}
*p_ptr = tmp;
...
}
...
}
int main(void) {
char *p = NULL;
f(&p);
...
free(p);
}
I am creating a deque to store stings in C, and when I call the free() function, the program crashes. I have implemented a similar structure but only storing integers, and encountered no problems, but this seems to be causing me a few. I created a struct containing a multidimensional array or characters, and i think maybe I am not using the pointers correctly? I have searched far and wide and cannot solve it The main area of concern is when i call clear() from the ain body. That in turn calls free(), and the program just stalls. :-( Any help would be extremely useful.
#include <stdio.h>
#define MAX 20 // number of characters for word
typedef struct {
char **deque;
int size;
int pFront;
int pRear;
} deque;
typedef int bool;
enum { false, true };
void initDeque(deque *d, int initialSize)
{
d->size = initialSize;
d->pFront = -1;
d->pRear = -1;
d->deque = (char **)malloc(sizeof(char*)*initialSize);
int idx;
for(int idx = 0; idx < d->size; idx++)
{
d->deque[idx] = (char *)malloc((MAX+1) * sizeof(char));
d->deque[idx] = "";
}
printf("d->size: %zu\n", d->size);
}
void clear(deque *d) {
if(d->pFront == -1)
{
printf("Queue is empty\n");
}
else
{
printf("Attempting to clear...\n");
for(int idx = 0; idx < d->size; idx++)
{
printf("Attempting to clear columns...");
free(d->deque[idx]);
}
printf("Attempting to clear rows...");
free(d->deque);
printf("Freed!!!!\n");
d->deque = NULL;
d->size = 0;
d->pFront = -1;
d->pRear = -1;
}
}
bool isEmpty(deque *d)
{
if(d->pFront == -1){
return true;
}
else
{
return false;
}
}
bool isFull(deque *d)
{
if(d->size == d->pRear+1)
{
return true;
}
else
{
return false;
}
}
void display(deque *d)
{
if(isEmpty(d)){
printf("empty\n");
}
else{
printf("Deque Values:\n");
int idx;
for(int idx = 0; idx <= d->pRear; idx++)
{
printf("Index: %zu\tValue: %s\n", idx, d->deque[idx]);
}
printf("Size: %zu\n", d->size);
}
}
void rAppend(deque *d, char item[]) // as in rear append - same enqueue for queue structure.
{
if(isFull(d))
{
printf("Is Full\n");
int idx;
deque dTemp;
initDeque(&dTemp, d->size);
printf("dTemp Initialised\n");
for(idx = 0; idx < d->size; idx++)
{
dTemp.deque[idx] = d->deque[idx];
}
printf("deque copied to dTemp:\n");
for(idx = 0; idx < d->size; idx++)
{
printf("dTemp[%zu]: %s\n", idx, dTemp.deque[idx]);
}
clear(&d);
printf("d cleared\n");
initDeque(&d, dTemp.size*2);
printf("New deque of double length initialised\n");
for(idx = 0; idx < dTemp.size; idx++)
{
d->deque[idx] = d->deque[idx];
}
printf("dTemp Copied to new deque\n");
clear(&dTemp);
printf("dTemp Cleared\n");
char **tmp = realloc( d->deque, sizeof (d->deque) * (d->size*2) );
if (tmp)
{
d->deque = tmp;
for (int i = 0; i < d->size; i++)
{
d->deque[d->size + i] = malloc( sizeof(char) * MAX );
}
}
}
printf("Appending to rear.. %s\n", item);
d->pRear++;
d->deque[d->pRear] = item;
if(d->pFront == -1)
d->pFront = 0;
}
int main(void)
{
deque d;
initDeque(&d, 5);
rAppend(&d, "when");
rAppend(&d, "will");
rAppend(&d, "wendy");
rAppend(&d, "walk");
rAppend(&d, "with");
display(&d);
clear(&d);
return 0;
}
The problem is your are calling free() on static chain "when", "will",...
You can replace insertion in the function void rAppend(deque *d, char item[]) :
d->deque[d->pRear] = item;
with:
d->deque[d->pRear] = strdup(item);
Doing like this chains are allocated in the heap and free from the heap.
After there is others problems in the code, but it run without crash.
The main problem seems to be that you don't appreciate the difference between copying / assigning pointers and copying / assigning the data to which they point. Secondarily, it seems you may not appreciate the utility of pointers that don't point to anything, especially null pointers. Some details follow.
You are dynamically allocating space for a bunch of strings ...
for(int idx = 0; idx < d->size; idx++)
{
d->deque[idx] = (char *)malloc((MAX+1) * sizeof(char));
... and then leaking all of that space by replacing the pointer to each with a pointer to an empty string literal:
d->deque[idx] = "";
}
As if the leak were not bad enough, you are not permitted to free a string literal or modify its content, which you nevertheless try to do to any of those pointers that remain in the dequeue whenever you clear() it. This is likely the cause of some of your errors.
If you want to set each allocated string to an empty one then modify its content instead of replacing the pointer to it. For example:
d->deque[idx][0] = '\0';
In fact, however, you probably don't need to do even that. You are already performing bookkeeping to know which arrays contain valid (string) data and which don't, and that should be sufficient to do the right thing. Supposing you maintain copies of the strings in the first place.
But that's not all. When you rAppend() elements to your deque you have a similar problem. You create a temporary deque, and then copy the string pointers from your original deque into the temporary:
dTemp.deque[idx] = d->deque[idx];
Not only does this leak the original (empty) data in the temporary deque, it aliases that deque's contents with the main deque's. When you later clear the temporary deque, therefore, you free all the string pointers in the original. Subsequently using or freeing them produces undefined behavior.
Perhaps you instead want to strcpy() all the elements of the main deque into the temp and back, but I suggest instead skipping the temp deque altogether with something along these lines:
void rAppend(deque *d, char item[]) // as in rear append - same enqueue for queue structure.
{
if(isFull(d))
{
printf("Is Full\n");
char **tmp = realloc(d.deque, d->size * 2);
if (tmp)
{
d->deque = tmp;
for (int i = 0; i < d->size; i++)
{
// Copied from the original, but see below
d->deque[d->size + i] = malloc( sizeof(char) * MAX );
}
d->size * 2;
} // else?
}
printf("Appending to rear.. %s\n", item);
d->pRear++;
// Oops, this is another leak / aliasing issue:
d->deque[d->pRear] = item;
if(d->pFront == -1)
d->pFront = 0;
}
The whole point of the temporary deque is lost on me, since the realloc() you need to do preserves the original data anyway (as long as it succeeds, anyway).
Note too, however, that this still has an aliasing issue: you have aliased a deque element with the appended string, and leaked the memory allocated for that element. Furthermore, when you clear the deque, you free that string for everyone holding a pointer to it. Or at least you attempt to do so. You're not permitted to do that to string literals.
I suggest not allocating space in your deque for the individual strings at all, and not freeing it. Continue to use assignment to store elements in your deque, understanding and embracing that these are aliases. This will be more analogous to your implementation for ints.
#include<memory>
#include<iostream>
using namespace std;
struct S {
S() { cout << "make an S\n"; }
~S() { cout << "destroy an S\n"; }
S(const S&) { cout << "copy initialize an S\n"; }
S& operator=(const S&) { cout << "copy assign an S\n"; }
};
S* f()
{
return new S; // who is responsible for deleting this S?
};
unique_ptr<S> g()
{
return make_unique<S>(); // explicitly transfer responsibility for deleting this S
}
int main()
{
cout << "start main\n";
S* p = f();
cout << "after f() before g()\n";
// S* q = g(); // this error would be caught by the compiler
unique_ptr<S> q = g();
cout << "exit main\n";
// leaks *p
// implicitly deletes *q
}
I'm working on a homework assignment and I need to basically create a character buffer. One of the functions I need to create is called "b_reset". It's purpose is to reinitialize the given buffer so that it will point to the first position in the char buffer. This is needed because later on, when a new char is added to the buffer, it needs to be added to the first position in the buffer.
This is the code I have thus far:
The struct:
typedef struct BufferDescriptor {
char * ca_head ;
int capacity ;
char inc_factor;
int addc_offset ;
int mark_offset ;
char r_flag;
char mode;
} Buffer ;
The code:
int b_reset ( Buffer *pB )
{
Buffer *temp = NULL;
int i = 0;
int j = 1;
if (pB == NULL)
{
return R_FAIL_1;
}
else
{
temp = (Buffer*)malloc(sizeof(Buffer*));
if (temp == NULL)
{
return R_FAIL_1;
}
temp->ca_head = (char*)malloc(pB->capacity);
if (!temp->ca_head)
{
temp = NULL;
return R_FAIL_1;
}
for(i = 0;i < ca_getsize(pB);++i)
{
temp->ca_head[j] = pB->ca_head[i];
j++;
}
pB->ca_head = temp->ca_head;
//free(temp->ca_head);
//free(temp);
return 0;
}
}
My goal in this code was to create a temporary buffer that would basically shift over everything 1 time based on the actual given buffer. This would make the first position empty so another char could be added.
The problem I'm running into is that the original buffer doesn't seem to be returning the right values after I reset it.
When I do this for example:
temp->ca_head[0] = 'a';
temp->ca_head[1] = 'b';
temp->ca_head[2] = 'c';
temp->ca_head[3] = 'd';
temp->ca_head[4] = 'e';
b_reset(temp); //this will return the size as 0, when it's actually 5
//temp->ca_head[0] = 'i'; //if this is executed, it returns the size as 6
//and prints out the right values, but if it's not,
//it will not print out anything
printf("%d", ca_getsize(temp));
for(i = 0;i < ca_getsize(temp);++i)
{
printf("%c", temp->ca_head[i]);
}
I know something is going wrong here, but I'm not too sure what. Any suggestions would be greatly appreciated.
This code is based on your followup comment:
well I'm not trying to resize the buffer, I just want to create an
empty space in the first position, so basically shifting everything to
the right 1 time. The assumption is that there is a enough space in
the buffer to handle this process.
I don't think you need to do any malloc() ing beyond the initial one. You can just shift everything up in a loop:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define R_FAIL_1 1
#define BUFFER_SIZE 10
typedef struct BufferDescriptor {
char * ca_head ;
int capacity ;
char inc_factor;
int addc_offset ;
int mark_offset ;
char r_flag;
char mode;
} Buffer ;
void allocate_buffer(Buffer *pB, int size)
{
pB->ca_head = malloc(size);
assert(pB->ca_head);
pB->capacity = size;
}
int ca_getsize( Buffer *pB)
{
return pB->capacity;
}
int b_reset ( Buffer *pB )
{
int i = 0;
if (pB == NULL)
{
return R_FAIL_1;
}
else
{
if ( ca_getsize(pB) <= 0 || pB->ca_head == NULL )
return R_FAIL_1;
}
// shift data up by 1 byte
for( i = ca_getsize(pB) - 1 ; i > 0;i-- )
{
pB->ca_head[i] = pB->ca_head[i-1];
}
pB->ca_head[0] = '\0';
return 0;
}
void print_buffer(Buffer *pB)
{
printf("capacity: %d \n", ca_getsize(pB));
for (int i = 0;i < ca_getsize(pB);++i)
{
printf("buffer(%d): [%d] ",i, pB->ca_head[i]);
}
printf("\n");
}
int main(void)
{
Buffer a_buffer;
allocate_buffer(&a_buffer,BUFFER_SIZE);
strcpy(a_buffer.ca_head,"abcdefgh");
print_buffer(&a_buffer);
int ret = b_reset(&a_buffer);
assert(ret == 0);
print_buffer(&a_buffer);
}
temp = (Buffer*)malloc(sizeof(Buffer*));
You need to allocate enough space to hold a Buffer, but you only allocate enough space to hold a pointer to a buffer. This should be:
temp = (Buffer*)malloc(sizeof(Buffer));
You are managing your memory incorrectly. You are allocating memory for a new Buffer struct when actually you only need to handle the memory of the ca_head member (if my interpretation of your homework problem is correct).
Each time you invoke b_reset, you will allocate memory for this struct that will not be released. If you don't handle your memory correctly, you will experience unexpected results as the one you are reporting in your question.
I suggest you to make a research on the function realloc and use it properly in your b_reset function.
Good luck with your homework.
I'm trying to implement a stack structure in C, for storing char arrays into.
I have the following code:
typedef struct {
size_t size;
char **data;
} loods1;
loods1 *init(void) {
loods1 *loods = malloc(sizeof(loods1));
loods->data = malloc(sizeof(char *) * STACK_MAX);
for (int i = 0; i < STACK_MAX; i++) {
*(loods->data + i) = malloc(LABEL_LENGTH_MAX * sizeof(char));
}
loods->size = 0;
if (loods == NULL) {
perror("malloc failed\n");
return NULL;
}
return loods;
}
int empty(loods1 *loods) {
return (loods->size == 0);
}
void push(loods1 *loods, char *name) {
if (loods->size == STACK_MAX) {
perror("Stack is full\n");
exit(0);
}
else {
*((loods->data) + loods->size++) = name;
}
}
char *pop(loods1 *loods) {
if (loods->size == 0) {
printf("size == 0\n");
return NULL;
}
else {
printf("%s \n", *(loods->data + 1));
return *(loods->data + (--loods->size));
}
}
int delete(loods1 *loods) {
for (int i = 0; i < STACK_MAX; i++) {
free(*(loods->data + i));
}
free(loods->data);
free(loods);
}
There are 2 problems: first off, every time I add a new element to the stack, it overwrites all existing elements (if '3' and '11' are added and I want to add '15', the new stack will look like '15', '15', '15'). And when I want to pop the stack, the popped value is empty. Not null, but an empty string or something?
I have no idea what I'm doing wrong, but there seems to be a mistake somewhere, obviously.
Sammy
In push function, if you are passing char*, it will divert your pointer to where the char * is, and when you do p++, it will go from the char* you passed.
Try change push definition to:
void push(loods1 *loods, const char *name) {
if (loods->size == STACK_MAX) {
perror("Stack is full\n");
exit(0);
}
else {
strcpy((loods->data)[loods->size++], name);
}
}
From here you might as well need some other changes to your calling program.
Also when you free it, free the single loods does not free all memory you allocated.
I flicked through the code and it seems to be ok, I think the problem is in your client.
Your only store pointers in the stack, you're probably pushing the same pointer on the stack but rewrite the string it points to.
Note that if you really only want to store pointers your 3rd malloc is wasting space and also creates a memory leak.
Learning C and having many doubts.
I have a function (lets say function 1) that calls another function (lets say function 2).
Function 2 calculates an array of string.
How can I use this array in function 1?
Some code example:
int find_errors(char* word)
{
char error[100];
/*Given the word, It will find the duplicate chars and store it in the
error array. */
return 0;
}
int find_word(char* word)
{
find_errors (word);
printf("%s\n", error);
return 0;
}
There are at least three possible approaches:
Use a global variable
pass a parameter between them
return a pointer from the function
There are multiple ways to do this.
1) Create a dynamic array and return a pointer to the array. This will require you to manually free the memory for the array at a later time.
#define NUM_ELEMS 50
// In find_error():
char* error = malloc(NUM_ELEMS * sizeof(char));
return error;
// In find_word():
char *error = find_errors();
// do stuff
free(error);
2) Pass a pointer to find_errors that it can use as the error array. This will not require you to manually free the memory.
// In find_word():
char error[NUM_ELEMS];
find_error(error);
3) Use a global array. May make it more difficult for other people to understand your code. Has other potential problems as well.
// In global scope:
char error[NUM_ELEMS];
Your question relates to "call-by-reference" and "call-by-value".
char* getNewValsToSet(void)
{
char* new_vals = (char*) malloc(sizeof(char[5]));
new_vals[4] = '\0';
return new_vals;
}
void setValuesEven(char* vals_to_set)
{
vals_to_set[0] = 'A';
vals_to_set[2] = 'C';
}
void setValuesOdd(char* vals_to_set)
{
vals_to_set[1] = 'B';
vals_to_set[3] = 'D';
}
int main(void)
{
char* some_vals_to_set = getNewValsToSet();
setValsEven(some_vals_to_set);
setValsOdd(some_vals_to_set);
// ... now has vals "ABCD"
free(some_vals_to_set); //cleanup
return 0;
}
If you have "doubts" about learning C, IMHO it's one of the best things you can do (no matter the language in which you work) because it will explain exactly how things work "under-the-hood" (which all high-level languages try to hide to some degree).
You need to declare the error array globally and use it just like you did.
EDIT: using global variables isn't the best practice in most of the cases, like this one.
Here is an example of what you are looking for with an awesome console output. It dynamically allocates the array to hold any number errors (duplicate characters in your case) that may occur.
//Only free errors if result is > 0
int find_errors(char* word, char** errors)
{
int num_errors = 0;
int word_length = strlen(word);
int ARRAY_SIZE = MIN(8, word_length);
char existing[word_length];
int existing_index = 0;
*errors = NULL;
for(int i = 0; i < word_length; i++)
{
char character = word[i];
//Search array
for (int n = 0; n < word_length; ++n ) {
if(n >= existing_index)
{
existing[n] = character;
existing_index++;
break;
}
if (existing[n] == character) {
num_errors++;
if(!*errors)
*errors = (char*)malloc(ARRAY_SIZE * sizeof(char));
//Check if we need to resize array
if(num_errors >= ARRAY_SIZE)
{
ARRAY_SIZE *= 2;
ARRAY_SIZE = MIN(ARRAY_SIZE, word_length);
char *tmp = (char*)malloc(ARRAY_SIZE * sizeof(char));
memcpy(tmp, *errors, (unsigned long)ARRAY_SIZE);
free(*errors);
*errors = tmp;
}
//Set the error character
(*errors)[num_errors - 1] = character;
break;
}
}
}
return num_errors;
}
int find_word(char* word)
{
char* errors;
int errCount = find_errors (word, &errors);
if(errCount > 0)
{
printf("Invalid Characters: ");
for(int i =0; i < errCount; i++)
{
printf("%c ", errors[i]);
}
printf("\n");
free(errors);
}
return 0;
}
int main(int argc, char *argv[])
{
find_word("YWPEIT");
find_word("Hello World");
find_word("XxxxXXxXXoooooooOOOOOOOOOOOOOOOooooooooOOOOOOOOOOOOooooooOOO");
}