Change a dynamic 2D char array through a function in C? - c

I'm creating this sample run so I can better understand how I can edit dynamic arrays through other functions, but I started running into segfaults once I added the secondary function.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void other_side(char ***funk);
int main()
{
int i;
char *argv[11] = {"fish", "dish", "lags", "fags", "shag", "cool", "bean", "rekt", "noon", "coon", "lolz"};
char **yep, **nop;
yep = malloc(10 * sizeof *yep);
if(!yep) { // <-----------------added check for malloc error
printf("Error: failure to allocate memory\n");
exit(1);
}
printf("10 times %lu\n\n", sizeof *yep);
for(i = 0; i<10; i++) {
yep[i] = strdup(argv[i]);
printf("%s is in yep.\n", *(yep+i));
}
nop = realloc(yep, 11 * sizeof *yep); //you reallocate to the new total size.
if(nop == NULL) {
printf("Error: failure to allocate memory\n")
exit(1);
}
yep = nop;
*(yep+10) = strdup(argv[10]);
printf("Last but certainly not least, %s is in yep.\n", *(yep+10));
printf("Now to send yep over to the other side and have its values changed.\n");
other_side(&yep);
printf("Did it change?\n\n");
for(i=0; i<11; i++)
printf("%s is in yep.\n", *(yep+i));
for(i=0; i<11; i++) { //issue fixed when added strdup() above, previously static
free(*(yep+i));
}
free(yep);
return 0;
}
void other_side(char ***funk)
{
char *arr[11] = {"dude","yeah","gnar","nice","epic","need","more", "word","four","this","test"};
int i;
for(i=0; i<11; i++) {
**(funk+i) = strdup(arr[i]); //added strdup() here as well
printf("%s is currently in yep.\n", **(funk+i));
}
printf("\n");
}
A couple things I noticed with this is that Valgrind notices an unnecessary free when I try to free the 11th block of memory to my array in main(). I'm not sure if that's my issue, but I also noticed that the function will only change two words before it leads to a segmentation fault.
Edit Notes: Since the edit I still get segfaults, but valgrind has been a bit more clear with what is happening. (Bad permissions for mapped region at address 0x400B18)

Your order of precedence regarding operators is important, and you missed a pair of parens to ensure it is done correctly. This: **(funk+i) means this: *(funk[i]), not (*funk)[i] which is what you want.
This:
**(funk+i) = strdup(arr[i]);
printf("%s is currently in yep.\n", **(funk+i));
Should be this:
*((*funk)+i) = strdup(arr[i]);
printf("%s is currently in yep.\n", *((*funk)+i));
and frankly, it is considerably easier to read as:
(*funk)[i] = strdup(arr[i]);
printf("%s is currently in yep.\n", (*funk)[i]);
I leave the rest of the memory management to you to fix. (i.e. the leaks from the dynamic memory pointed to by all the pointers you're overwriting in the above loop code).

Related

(C) Using Arrays with Dynamic memory allocation

I want to create a simple array of integers having 10 elements.
I'm using dynamic memory to allocate a space in memory and whenever I exceed that amount It will call realloc to double its size.
Whenever I type 'q' it will exit the loop and print the array.
I know my program is full of bugs, so please guide me into where I'm going wrong.
/* Simple example of dynamic memory allocation */
/* When array reaches 10 elements, it calls
realloc to double the memory space available */
#include <stdio.h>
#include <stdlib.h>
#define SIZE_ARRAY 10
int main()
{
int *a;
int length=0,i=0,ch;
a= calloc(SIZE_ARRAY, sizeof(int));
if(a == NULL)
{
printf("Not enough space. Allocation failed.\n");
exit(0);
}
printf("Fill up your array: ");
while(1)
{
scanf("%d",&ch);
if(ch == 'q') //possible mistake here
break;
a[length]=ch;
length++;
if(length % 10 == 0) //when length is 10, 20, 30 ..
{
printf("Calling realloc to double size.\n");
a=realloc(a, 2*SIZE_ARRAY*sizeof(int));
}
}
printf("You array is: \n");
for(;i<length;i++)
printf("%d ",a[i]);
return 0;
}
Whenever I type 'q' the program crashes. I'm a beginner so I know I'm doing a dumb mistake. Any help would be greatly appreciated.
You should not double the memory every realloc() that can get very large, very quick. You normally expand the memory by small chunks only. realloc() also has the nasty habit to use another part of the memory if the old one cannot be elongated enough. If that fails you loose all of your data in the old memory. This can be avoided by using a temporary pointer to point to the new memory and swap them after a successful allocation. That comes with the cost of just on extra pointer (mostly 4 or 8 bytes) and a swap (needing only a handful of CPU cycles at most. Be careful with x86's xchg it uses a lock in case of multiple processors which is quite expensive!)
#include <stdio.h>
#include <stdlib.h>
// would normally be some small power of two, like
// e.g.: 64 or 256
#define REALLOC_GROW 10
int main()
{
// a needs to be NULL to avoid a first malloc()
int *a = NULL, *cp;
// to avoid complications allocated is int instead of size_t
int allocated = 0, length = 0, i, ch, r;
printf("Fill up your array: ");
while (1) {
// Will also do the first allocation when allocated == length
if (allocated <= length) {
// realloc() might choose another chunk of memory, so
// it is safer to work on copy here, such that nothing is lost
cp = realloc(a, (allocated + REALLOC_GROW) * sizeof(int));
if (cp == NULL) {
fprintf(stderr, "Malloc failed\n");
// but we can still use the old data
for (i = 0; i < length; i++) {
printf("%d ", a[i]);
}
// that we still have the old data means that we need to
// free that memory, too
free(a);
exit(EXIT_FAILURE);
}
a = cp;
// don't forget to keep the amount of memory we've just allocated
allocated += REALLOC_GROW;
}
// out, if user typed in anything but an integer
if ((r = scanf("%d", &ch)) != 1) {
break;
}
a[length] = ch;
length++;
}
printf("Your array is: \n");
// keep informations together, set i=0 in the loop
for (i = 0; i < length; i++) {
printf("%d ", a[i]);
}
fputc('\n', stdout);
// clean up
free(a);
exit(EXIT_SUCCESS);
}
If you play around a bit with the start-value of allocated, the value of REALLOC_GROW and use multiplication instead of addition in the realloc() and replace the if(allocated <= length) with if(1) you can trigger the no-memory error and see if it still prints what you typed in before. Now change the realloc-on-copy by using a directly and see if it prints the data. That still might be the case but it is not guaranteed anymore.

segmentation 11 in C

I'm writing a homework program in C. The program should take records from an input file and write those record to an output file. It seems like there is something wrong with the print_to_file function. I keep getting segmentation fault 11. Please help. My code is as below.
#include <stdio.h>
#include <stdlib.h>
typedef struct car { // create a struct type Car
char *license_plate;
int parking_spot;
int num_tickets;
int time_left;
} Car;
#define LICENSEPLATELENGTH 10
Car* import_cars(char *filename, int numCars);
void print_to_file(char* filename, Car* garage, int numCars);
int main(int argc, char * argv[]) {
if(argc != 4)
printf("Incorrect input.\n");
else {
int number = atoi(argv[1]);
Car* parked_car = (Car*)malloc(sizeof(Car) * number);
parked_car = import_cars(argv[2], number);
print_to_file(argv[3], parked_car, number);
free(parked_car);
}
return 0;
}
Car* import_cars(char* filename, int numCars)
{
Car* inCar = (Car*)malloc(sizeof(Car) * numCars);
inCar->license_plate = (char*)malloc(sizeof(char) * 8);
//Question: How do I do if I the plate length is varied. How to malloc space to it?
FILE* inFilePtr;
if((inFilePtr = fopen(filename, "r")) == NULL)
printf("Error! Unable to open file %s. Check again.\n", *filename);
else
{
int i = 0;
fscanf(inFilePtr, "%s", inCar[i].license_plate);
fscanf(inFilePtr, "%d%d%d", inCar[i].parking_spot, inCar[i].num_tickets, inCar[i].time_left);
printf("%s %d %d %d \n", inCar[i].license_plate, inCar[i].parking_spot, inCar[i].num_tickets, inCar[i].time_left);
for(i = 1; i < numCars; i++)
{
fscanf(inFilePtr, "%s", inCar[i].license_plate);
fscanf(inFilePtr, "%d%d%d", inCar[i].parking_spot, inCar[i].num_tickets, inCar[i].time_left);
printf("%s %d %d %d \n", inCar[i].license_plate, inCar[i].parking_spot, inCar[i].num_tickets, inCar[i].time_left);
}
}
fclose(inFilePtr);
return(inCar);
//free(inCar.license_plate); `
//Question: Do I need to free space here would it remove the value
//stored in the variable which passed to main?
}
void print_to_file(char* filename, Car* garage, int numCars) {
FILE* outFilePtr;
if((outFilePtr = fopen(filename, "w+")) == NULL){
printf("Error! Cannot Open File %s!", *filename);
printf("here\n");
} else {
int i = 0;
for(i = 0; i < numCars; i++) {
printf("%s\n%d %d %d\n", garage[i].license_plate, garage[i].parking_spot, garage[i].num_tickets, garage[i].time_left);
fprintf(outFilePtr, "%s\n%d %d %d\n", garage[i].license_plate, garage[i].parking_spot, garage[i].num_tickets, garage[i].time_left);
}
}
fclose(outFilePtr);
}
This is my input command.
./a.out 6 garage.txt output.txt
Here is what print in my terminal.
fi590dz 20 2 25
57fjgmc 8 0 55
7dkgjgu 25 1 15
f9e829d 1 2 60
4jgfd81 12 2 10
Segmentation fault: 11
By the way, I'm pretty new in programming and really bad with debugging. Could you give me some tips of how to debug or any debugging tools? I use a mac so gdb doesn't work.
Not a complete answer, because it’s a homework problem and you want to figure it out yourself, but here are some hints.
First, you really want to learn how to run your program in a debugger and get it to tell you which line crashed the program, and on which data.
Second, make sure you initialize the pointers for every element of the array before you try to read or write them.
Third, you’ll save yourself a lot of trouble if you initialize all your dynamic and local variables to zeroes, not garbage. It will make a lot of bugs reproducible, make a lot of bugs crash immediately instead of corrupting memory, and also make it obvious when you debug that you’re using uninitialized data.
Therefore, I suggest you get in the habit of allocating your dynamic arrays with calloc(), not malloc().
The problem lies within your parked_car = import_cars(argv[2], number); and Car* import_cars(char* filename, int numCars);functions.
Indeed in Car* import_cars(char* filename, int numCars); you are doing this:
Car inCar;
inCar.license_plate = (char*)malloc(sizeof(char) * 8);
So you are creating a local variable that is not accessible outside of the function (many different things can happen to the memory after the end of the function).
So when you do: parked_car = import_cars(argv[2], number); you are assigning to parked_car a freed variable.
A solution is to simply use the parked_caras an argument of your import_cars() function. All modifications made within the function will still be valid after it returns. So you should have:
void import_cars(char* filename, int numCars, Car* car);
For everyone who met the issue here, I found the problem in my program. The problem is that I didn't allocate space for each of the license_plate pointer in the structure. So my way to solve it is add a line as below in the for loop of the import_cars function.
inCar[i].license_plate = (char*)malloc(sizeof(char) * LICENSEPLATELENGTH);

Adding a struct to an array using a pointer

I am fairly new to the C language and allocating memory/using pointers in general. Anyway, I was experimenting with reading a file, putting those values in a struct, etc. I know exactly what I want to do and of course the program runs but the output is incorrect and some kind of jumbled numbers and letters.
There is a text file with new information for each line. Each line represents one object.
This is how a line in the file might look:
meat sirloin 6.55 8 8.50 4
Overall I want to be able to store all of my PRODUCT objects in an array (so I have an array of structs). So I attempted to allocate memory with a pointer, use a line count, and then send the pointer to a function called read. In read I add each struct to the array via a pointer. The program doesn't crash, the output is just not correct and I have no clue why not. It's prob something with pointers. If anyone could help me I would really appreciate it. Any help at all would be great.
//prototype
void read(pointerToArr);
typedef struct
{
char supType[15];
char prodName[15];
double wholePrice;
int quantWhole;
double retPrice;
int retProdQuantity;
}PRODUCT;
FILE *fr;
int lineCount = 0;
int main()
{
PRODUCT *ptr;
int i;
char check[50];
fr = fopen("ttt.txt", "r");
while(fgets(check, sizeof(check), fr)!= NULL)
{
if(check[0] != '\n')
{
lineCount++;
}
}
// allocate memory for array based on line count.
PRODUCT prodContainter[lineCount];
ptr = (PRODUCT*)malloc(sizeof(PRODUCT)*lineCount);
ptr = prodContainter;
read(ptr);
//print after adding to array via pointer from other
//function. this was a test.
for(i = 0; i < lineCount; i++)
{
printf("%s ", prodContainter[i].supType);
printf("%s ", prodContainter[i].prodName);
printf("%f ", prodContainter[i].wholePrice);
printf("%d ", prodContainter[i].quantWhole);
printf("%f ", prodContainter[i].retPrice);
printf("%d\n\n", prodContainter[i].retProdQuantity);
}
return 0;
}
void read(PRODUCT *pointerToArr)
{
// objective in this method is to read in data from the file, create an object for every line and
// then use the pointer array to add those objects to prodConstainer up above.
char supplyName[15];
char productName[15];
double wholeP = 0;
int quantityWhole = 0;
double retailPrice = 0;
int retailProductQuant = 0;
while(fscanf(fr, "%s %s %lf %d %lf %d", supplyName, productName, &wholeP, &quantityWhole, &retailPrice, &retailProductQuant) == 6)
{
PRODUCT record;
int i;
strcpy(record.supType, supplyName);
strcpy(record.prodName, productName);
record.wholePrice = wholeP;
record.quantWhole = quantityWhole;
record.retPrice = retailPrice;
record.retProdQuantity = retailProductQuant;
for(i = 0; i < lineCount; i++)
{
pointerToArr[i] = record;
}
}
fclose(fr);
}
You never rewind the file, so all the reading after you count the number of lines fails.
What you're printing is just what happens to be in memory.
There are many ways to fix this, of course.
Rewind the file, using rewind()
Close the file and let your read() function (whose name collides with a POSIX standard function, btw) re-open the file. This would also involve removing the scary global variable fr.
Re-structure so you never count the number of lines, by just reading and letting the ptr array grow as necessary (see realloc()).
Also, you should really avoid casting the return value of malloc() in C. This:
ptr = (PRODUCT*)malloc(sizeof(PRODUCT)*lineCount);
is better written as:
ptr = malloc(lineCount * sizeof *ptr);
This does away with the cast, and also uses sizeof on a value of the type pointed at to automatically compute the proper number of bytes to allocate.

Segmentation fault in C, malloc array

I have problem with my school project, the server which is testing this build returns this error:
./__runscript: line 2: 489 Segmentation fault ./a.out < __input
Compile is OK, but this error is displayed just when it starts running. But if I run it on Windows 7 with visual studio 10, everything is fine. I think the mistake might be in the insert() function.
POSTUP *insert(POSTUP *first)
{
POSTUP* current,*pom;
current=(POSTUP*)malloc(sizeof(POSTUP));
pom=(POSTUP*)malloc(sizeof(POSTUP));
int i,count_of_elements;
scanf("%d", &count_of_elements);
if(first==NULL)
{
first=current;
first->array= (int*)malloc(count_of_elements*sizeof(int));
for(i=0; i<count_of_elements; i++)
{
scanf("%d",&first->array[i]);
}
first->elements=count_of_elements;
first->next=NULL;
return first;
}
else
{
pom->array= (int*)malloc(count_of_elements*sizeof(int));
for(i=0; i<count_of_elements; i++)
{
scanf("%d",&pom->array[i]);
}
pom->next=NULL;
pom->elements=count_of_elements;
current=first;
while(1)
{
if(current->next==NULL)
{
current->next=pom;
return first;
}
}
}
return 0;
}
int main(void)
{
int count, i;
POSTUP* first,*current;
first= (POSTUP*)malloc(sizeof(POSTUP));
first=NULL;
scanf("%d",&count);
for(i=0; i<count; i++)
{
first=insert(first);
}
}
This code in main():
POSTUP *first, *current;
first = (POSTUP*)malloc(sizeof(POSTUP));
first = NULL;
scanf("%d", &count);
for (i = 0; i < count; i++)
{
first = insert(first);
}
is clearly problematic. You allocate space and store the only pointer to it in first; you then overwrite the pointer, leaking memory. You should officially check that the allocation was not null. But your insert() code is equipped to handle a null pointer as input, so the memory allocation in main is redundant.
In insert(), you allocate memory without checking for success; this is a recipe for trouble, though more usually later than sooner.
Your code is never checking the result of scanf(); that means you could be getting rubbish into your system if there's a format error in the data.
Likely cause of crash: In the 'if (first == NULL)block ininsert()`, you have:
for(i=0; i<count_of_elements; i++)
{
scanf("%d", &prvy->array[i]);
}
There's no declaration of prvy in sight in the code you show; it should almost certainly be referring to &first->array[i] anyway. This could easily be good for a crash. Otherwise, you've carefully stashed the data in a different set of memory than you thought, so the array for first is uninitialized gibberish.
The same code does not use pom, so you've leaked memory in this part of the code.
In the main else clause in insert(), you overwrite current (which contained a memory allocation) with first, thus leaking memory there too.
Don't allocate memory until you're about to use it.

Freeing Object Error

I am mallocing an array of c strings. After releasing it, I get the following error:
Assembler(87536) malloc: *** error for object 0x108500840: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Why is that? I am pretty sure I am doing the malloc correctly. I'm pretty experienced with memory management, but I am not sure why this is giving me an error. The array is should hold three strings, each of which is 2 characters long.
Here is how I am mallocing the array:
char **reg_store;
reg_store = malloc(3 * (sizeof(char*)));
if (reg_store == NULL) {
fprintf(Out, "Out of memory\n");
exit(1);
}
for (int i = 0; i < 3; i++) {
reg_store[i] = malloc(2 * sizeof(char));
if (reg_store[i] == NULL) {
fprintf(Out, "Out of memory\n");
exit(1);
}
}
Here is how I am freeing it:
for (int i = 0; i < 3; i++) {
free(reg_store[i]);
}
free(reg_store);
Here is what I have in between:
// Keeps a reference to which register has been parsed for storage
int count = 0;
char *reg = NULL;
char *inst_ptr // POINTS TO SOME STRING. EXAMPLE: $t2, $t1, $a0
while (1) {
// Parses the string in inst_ptr with dollar, comma and space as a delimiter.
reg = parse_token(inst_ptr, " $,\n", &inst_ptr, NULL);
if (reg == NULL || *reg == '#') {
break;
}
reg_store[count] = reg;
count++;
free(reg);
}
I am printing out reg after I call parse_token and it does print out correctly. I am also printing out reg_store[count] and it does also print out correctly.
Your problem is here:
reg_store[count] = reg;
free(reg);
and later
free(reg_store[i]);
reg is already freed and you free it another time (not talking about the problems with using it later). to fix this replace
reg_store[count] = reg;
with
strcpy(reg_store[count], reg);
or as suggested in the comments, since you know its two charaters, its better to memcpy it:
memcpy(reg_store[count], reg, 2);
I would suggest adding some printfs (or use the debugger) to see the values of all the malloced pointers just after they have been malloced. Then do the same just before they are freed, to make sure they are the same. Perhaps there is some other rogue code elsewhere in the program that is stomping over memory.
Your problem is in the "in between" code, in particular, right here:
reg_store[count] = reg;
count++;
free(reg);
You allocated reg_store[count] with malloc during your set up, then you overwrite the allocated value with reg and then free reg. The result is a memory leak from the original pointers that were in reg_store and a double-free on each element of reg_store when you try to clean everything up.
You need to copy reg into the memory already allocated in reg_store[count] (watching the size of course) or don't allocate any space for the elements of reg_store before the "in between" code at all.
The error was already pointed out so no need to write it again.
I can however point out that i don't like the way you are handling errors.
void freeRegStore(char** reg_store)
{
int i;
if (reg_store != NULL)
{
for (i = 0; i < 3; i++)
free(reg_store[i]);
free(reg_store);
}
}
char** allocRegStore()
{
int i;
char **reg_store;
reg_store = calloc(3 * (sizeof(char*)), 1);
if (reg_store != NULL)
{
for (i = 0; i < 3; i++)
{
reg_store[i] = malloc(2 * sizeof(char));
if (reg_store[i] == NULL)
{
freeRegStore(reg_store);
return NULL;
}
}
}
return reg_store;
}
In this method, the function allocRegStore will return NULL if there was not enough memory without leaving pieces around.
Then you can handle this case in main and not in the allocation function itself.
I disagree with the use of printf and exit inside functions.
int main()
{
char** reg_store = allocRegStore();
if (reg_store == NULL)
{
puts("Out of memory");
return 1;
}
... do your stuff
freeRegStore();
return 0;
}
I can also say that the memory used by this program will never go out of memory :) i would not worry about that.

Resources