C - 2D Array malloc/free - Segmentation fault - c

I have a very simple snippet below for which I am trying to figure out the reason for getting a segmentation fault.
int main (int argc, char** argv)
{
const int size = 2;
char** test1 = NULL;
int index = 0;
test1=(char**)malloc(sizeof(char*) * size);
if (test1 != NULL)
{
for (index = 0; index < size ; index++)
{
test1[index]=(char*)malloc(sizeof(char));
test1[index]='a';
}
//Removing this block does not result in seg fault - start
for (index = 0 ; index < size ; index++)
{
free(test1[index]); //Seg. fault here
}
//Removing this block does not result in seg fault - end
free(test1);
}
return 0;
}
If I remove the block enclosed within start and end comment - I do not see seg fault. But I think that would result in a leak.
Any help is much appreciated.

I think you meant to dereference the test1[index]. Your code overwrites the address of the allocated memory with 'a', hence when it tries to free the memory it segs fault because 'a' is not a valid address.
test1[index]=(char*)malloc(sizeof(char));
*test1[index]='a';
This works as well
test1[index][0]='a';

You start out fine:
test1=(char**)malloc(sizeof(char*) * size);
if (test1 != NULL) {
Your loop is not:
for (index = 0; index < size ; index++) {
test1[index]=(char*)malloc(sizeof(char));
test1[index]='a';
}
First, you allocating only one byte for what is supposed to be a row of characters (since you have only one "size" variable, I assume you want your 2d array to be square: 2x2. So you need to multiply by size here like you did in the outer loop. You don't need "sizeof(char)", that's just a long-winded way of typing "1".
But worse than that, after allocating the row too short, you then throw that memory away by overwriting the pointer with a character (you should have gotten a compiler warning here). That's disaster waiting to happen and a memory leak.
What you really mean is:
for (index = 0; index < size ; index++) {
test1[index]=malloc(size);
test1[index][0]='a';
}

Related

Can someone please explain why I'm getting a seg fault error

This code compiles successfully but when I debug it shows a SIGSEV seg fault error. Can someone help please?
char *_strdup(char *str)
{
int i, size = 0;
char *mp;
if (str == NULL)
{
return (NULL);
}
for (; str[size] != '0'; size++)
mp = malloc(size * sizeof(str) + 1);
/* + 1 to get last part of the str */
if (mp == 0)
{
return (NULL);
}
else
{
for (; i < size; i++)
{
mp[i] = str[i];
}
}
return (mp);
}
First, just because it compiles successfully, this does not mean that your code is correct. It just means that syntactically the compiler is fine. I hope you use the maximum warning level and correct your code until all warnings and errors are gone.
You have multiple problems:
You seem to look for the terminating end-of-string marker. But instead of the correct '\0' you typed '0'. This can lead to a much too big size, depending where a zero digit is found. Depending on your system, a segmentation fault is also possible.
sizeof is an operator that yields the size of its argument, in your case the size of a pointer. str is of type char *. Effectively you allocate too much, but this is harmless.
The for loop uses the memory allocation as its body. I'm sure you didn't mean this, but there is no empty statement. So you are allocating multiple memory spaces, which are leaks in the end.
An empty statement is a single semicolon or an empty pair of curly braces.
What you most probably want to achieve is to find the number of characters that str points to. You can get it by calling strlen(str).
i is not initialized, it can have any value. This can lead to a segmentation fault, if it starts with a negative value.
You did not add the end-of-string marker in the duplicate. Depending on the other code we don't see, this can lead to segmentation faults.
This is a possible solution without calling strlen():
char *_strdup(const char *str)
{
int i;
int size;
char *mp;
if (str == NULL)
{
return NULL;
}
for (size = 0; str[size] != '\0'; size++)
{
/* just looking for the end of the string */
}
size++;
/* + 1 for the end-of-string marker */
mp = malloc(size);
if (mp == NULL)
{
return NULL;
}
for (i = 0; i < size; i++)
{
mp[i] = str[i];
}
return mp;
}
I made a bit more:
Use separate variable definitions, it avoid errors and eases maintenance.
return is not a function and needs no parentheses for its expression.
Put the initialization of the index variable where it belongs, in the initializing statement of for. This way everything about this index is at one place.
Consider the end-of-string marker by incrementing size. This eases the following code.
Since sizeof (char) is 1, it can be ommitted at the calculation of the needed memory size.
Compare mp with NULL instead of 0. It is a pointer, and this is C, not C++.
Your variable i has been declared but not initialized so a random number is used in your for(; i < size;
Just add int i = 0, size = 0; at the beginning or change your for statement to for(i = 0; i < size; i++)
This was the reason for your segmentation fault. Some other issues:
As mentioned in comments string termination character is not '0'. It's either 0 or '\0'.
You are calling malloc on each iteration of your for statement. This causes memory leak.Just call it once after you got your string size right. This is fixed by putting a semicolon after the for.
Maybe something like this.
char *_strdup (char *str)
{
int i, size;
char *mp;
if (str == NULL)
{
return (NULL);
}
for (size = 0; str[size] != 0; size++);
mp = malloc (size * sizeof (str) + 1);
/* + 1 to get last part of the str */
if (mp == 0)
{
return (NULL);
}
else
{
for (i = 0; i < size; i++)
{
mp[i] = str[i];
}
}
return (mp);
}

Exception raised while transposing 2D array

I am trying to transpose a 2D char array (in C) of unknown size rows and columns at run time. I use malloc to create the array and for loops to copy the chars form the original array to the new array. I am testing on a sample array of size 9x15 to create an array of 15x9 and the code works until my outer loop i =11 and then crash. In debug mode it shows Exception: Access violation writing to location 0xcdcdcdcd. The original array is read in from a file and is created using the same malloc code and works just fine. I have tried moving the code to main, but get the same exception. I am confused on how it does not create the array properly and would appreciate some input on how to correct the code or trouble shoot the issue better. My code is here
char **dest_grid = malloc(sizeof(char*) * source_col);
if (dest_grid == NULL) {
printf("Memory not assigned\n");
exit(EXIT_FAILURE);
}
else {
for (i = 0; i <= source_row; i++) {
dest_grid[i] = malloc(sizeof(char) * source_row);
}
for (i = 0; i < source_col; i++) {
for (j = 0; j < source_row; j++) {
if (j == source_row) {
dest_grid[i][j] = '\0';
}
else {
dest_grid[i][j] = source_grid[j][i];
}
}
}
}
for (i = 0; i < source_col; i++) {
free(dest_grid[i]);
}
free(dest_grid);
edit: The size of the array is provided from the file when read into memory. Multiple arrays are read in from the file of various sizes.
After char **dest_grid = malloc(sizeof(char*) * src_c); allocates space for src_c pointers, the loop beginning for (i = 0; i <= src_r; i++) attempts to fill it in with src_r+1 pointers, which is wrong.
if (dest_grid == NULL) tests for memory allocation failure, but this is after dest_grid was already used, in assigning values to dest_grid[i].
There is no code to test whether the memory allocations for dest_grid[i] fail.
dest_grid[i][j] = NULL; should be dest_grid[i][j] = '\0';, because NULL represents a null pointer, not a null character, and some definitions of it may cause compiler errors in this use.
free(dest_grid); releases the memory allocated to dest_grid, but the individual allocations to dest_grid[i] have not been freed.

Runtime error: reading uninitialized value, how can I fix it?

This function is basically just supposed to compare 2 strings and return their ASCII difference if they are different. It works perfectly fine when I compile it with the GCC compiler, but when I run it through the online compiler that is used to upload our classes homework, I get this error message:
Error near line 98: Reading an uninitialized value from address 10290
Line 98 is marked in the below code. I am not quite sure what the problem is and how I'm supposed to fix it. Does anyone have an idea?
int stringCompare(char * pStr1, char * pStr2) {
int n = 100;
int difference;
for (int i = 0; i < n; i++) {
difference = pStr1[i] - pStr2[i]; // line 98
if (difference != 0) {
return difference;
}
}
return difference;
}
Your code can skip over EOLN, if string equals, and try to compare memory after end of lines. To fix this, you need instantly return, if both string equals, and you see EOLN char '\0' in both strings at position i. Try my fix:
int stringCompare(char * pStr1, char * pStr2) {
int n = 100;
int difference;
for (int i = 0; i < n; i++) {
difference = pStr1[i] - pStr2[i];
if (difference != 0 || pStr1[i] == '\0') {
return difference;
}
}
return difference;
}
The problem in your code is that you fail to check the real length of the strings before indexing them. You are iterating with i from 0 to 99, but you do not check for the NUL terminator (\0) that marks the end of a string and therefore your for loop goes beyond the end of the string resulting in undefined behavior accessing memory that is not supposed to (which is what the error is telling you).
The correct way to iterate over a string, is not to loop a fixed amount of cycles: you should start from index 0 and check each character of the string in the loop condition. When you find \0, you stop. See also How to iterate over a string in C?.
Here's a correct version of your code:
int stringCompare(char *pStr1, char *pStr2) {
size_t i;
for (i = 0; pStr1[i] != '\0' && pStr2[i] != '\0'; i++) {
if (pStr1[i] != pStr2[i])
break;
}
return pStr1[i] - pStr2[i];
}
You could even write this more concisely with a simple while loop:
int stringCompare(char *pStr1, char *pStr2) {
while (*pStr1 && *pStr1 == *pStr2) {
pStr1++;
pStr2++;
}
return *pStr1 - *pStr2;
}
Of course, both the above functions expect two valid pointers to be passed as arguments. If you also want to allow invalid pointers you should check them before starting the loop (though it does not seem like you want to do that from your code).

Segmentation fault (core dumped) error, in a C search function

I'm trying to write a C program to take an array of discrete positive integers and find the length of the longest increasing subsequence.
'int* a' is the array of randomly generated integers, which is of length 'int b'
call:
lis_n = answer(seq, seq_size);
function:
int answer(int* a, int b) {
if (a == NULL) {return -1;}
int i = 0;
int j = 0;
int k = 0;
//instantiate max and set it to 0
int max = 0;
//make an array storing all included numbers
int included[b];
memset(included, 0, b*sizeof(int));
//create a pointer to the index in included[] with the largest value
int indexMax = 0;
//create a pointer to the index in a[]
int indexArray = 0;
//index of a[] for max included
int maxToA = 0;
//set the first included number to the first element in a[]
included[indexMax] = a[indexArray];
//loop until break
while (1) {
if (a[indexArray] > included[indexMax]/*digit greater than last included*/) {
//include the digit
included[indexMax+1] = a[indexArray];
//increment current max pointer
indexMax++;
}
j = b - 1;
while (indexArray >= j/*pointer is at end"*/) {
if (j == (b - 1)) {
if ((indexMax+1) > max/*total is greater than current max*/) {
max = indexMax + 1;
}
}
if (a[b-1] == included[0]/*last element is in included[0], stop*/) {
return max;
} else {
//max included is set to zero
included[indexMax] = 0;
//max included pointer decreased
indexMax--;
//set array pointer to new max included
for (k=0;k<(b-1);k++) {
if (a[k] == included[indexMax]) {
indexArray = k;
}
}
//increment array pointer
indexArray++;
j--;
}
}
indexArray++;
printf("(");
for (i=0;i<b;i++) {
printf("%d,",included[i]);
}
printf(")");
}
}
I'm receiving 'Segmentation fault (core dumped)' in the terminal upon running.
Any help would be awesome.
You have declared
int indexMax = 0;
And here you use it as an array index
incuded[indexMax] = 0;
You increment and decrement it
indexMax++;
...
indexMax--;
You check its range but you don't limit it, you alter the value you compare it with
if ((indexMax+1) > max/*total is greater than current max*/) {
max = indexMax + 1;
}
You never check indexMax against b or with 0
int included[b];
So you are almost guaranteed to exceed the bounds of included[].
Some general points of advice. Make your function and variable names meaningful. Avoid making a premature exit from a function wherever possible. Avoid while(1) wherever possible. And never make assumptions about array sizes (including C "strings"). It might seem hard work putting in the overhead, but there is a payoff. The payoff is not just about catching unexpected errors, it makes you think about the code you are writing as you do it.
I've done something like this for homework before. I got help from:
https://codereview.stackexchange.com/questions/30491/maximum-subarray-problem-iterative-on-algorithm
Make sure you are not trying to index past the size of your array. What I would do would be to find out the size of array a[] (which looks like it is b) and subtract 1. Make sure you are not trying to access past the size of the array.

Casting Double Pointer and How to utilize in C

Here is basically a simple code of double pointer and what I am trying to use:
int argsCount = 1;
char **cmdArgs1 = malloc((argsCount + 1)*sizeof(char*));
I want to input values into the cmdArgs1 and here is basically what I am doing and causing seg fault
for(counter = 0; counter < argsCount; counter++)
{
strcpy(cmdArgs1[counter],"ls");
}
I'm thinking that I can't use "cmdArg1[counter]" to copy to "ls" because the double pointer doesn't work that way? I'm not sure...
Even I think it's a bit vague, but I don't know how to phrase the question well, I will try to update based on the comment. Thx!
Your cmdArgs1 is a pointer to a pointer, meaning that it is not enough to allocate space for the array itself. You need to allocate space for the individual arrays of characters (or for the individual C string).
You can do it in a separate call of malloc
for(counter = 0; counter < argsCount; counter++)
{
cmdArgs1[counter] = malloc(strlen("ls")+1); // +1 for null terminator
strcpy(cmdArgs1[counter], "ls");
}
or with strdup:
for(counter = 0; counter < argsCount; counter++)
{
cmdArgs1[counter] = strdup("ls");
}
In both cases your program is liable for freeing the elements of the array before freeing the array itself:
for(counter = 0; counter < argsCount; counter++)
{
free(cmdArgs1[counter]);
}
free(cmdArgs1);

Resources