Realloc Crashing on Passed Pointer - c

I can't seem to find a question that matches exactly what I'm doing, so here goes. Below is a cut down version of my C app down to where a problem lies. I know it's ugly code and missing a few error checks but it was just for me to figure out this problem. As it stand the sample below should convert all 'A's to 'BCDE's. The comments in the code describe the issue. (runMe is executed first)
int runMe2(char *in, char **buffer) {
long x;
long b_size = 0;
long i_size = 1000;
long i = 0;
char t_buffer[1006];
// Initial malloc small as it will grow
*buffer = (char *)malloc(2*sizeof(char));
strcpy(*buffer, "");
for (x = 0; x < 999; x++)
t_buffer[x] = 0;
for (x = 0; x < strlen(in); x++) {
if (i >= i_size) {
char *r_buffer;
b_size = b_size + 1006*sizeof(char);
i_size = 0;
// Here is where the problem is.
// The first time through, i=1000, b_size=1006 and everything is fine
// The second time throgh, i=1004, b_size=2012 and the heap crashes on the realloc
r_buffer = (char *)realloc(*buffer, b_size);
if (r_buffer == NULL)
exit(0);
*buffer = r_buffer;
strcat(*buffer, t_buffer);
for (x = 0; x < 999; x++)
t_buffer[x] = 0;
}
if (in[x] == 'A') {
t_buffer[i++] = 'B';
t_buffer[i++] = 'C';
t_buffer[i++] = 'D';
t_buffer[i++] = 'E';
}
}
}
int runMe() {
char *out;
char in[30000];
int x = 0;
// Set up a 29,999 character string
for (x = 0; x < 30000; x++)
in[x] = 'A';
in[29999] = 0;
// Send it as pointer so we can do other things here
runMe2(in, &out);
// Eventually, other things will happen here
free(out);
}

if (i >= i_size) {
...
i_size = 0;
...
}
if (in[x] == 'A') {
t_buffer[i++] = 'B';
...
This can't be right. You'll be writing past the end of t_buffer if in is ever longer than the original i_size. You probably meant to reset i there, not i_size.
Then you're using string functions with t_buffer when you've not guaranteed that it is properly null-terminated - you initialize the first thousand values, but overwrite those in your loop. If you're going to use strcat and friends, you need to take more care to make sure it stays null-terminated. But using memcpy would lead to simpler code since you know the lengths of the arrays involved.
for (x = 0; x < strlen(in); x++) {
...
for (x = 0; x < 999; x++)
...
t_buffer[x] = 0;
This can't be right either, as spotted by Useless. Use a second variable for that, or better use memset.

Just for fun here's a different algo that works and is much simpler than yours:
int runMe2(char *in, char **buffer)
{
// Count number of A's
int number_of_As = 0;
int i, j;
for (i = 0; 0 != in[i]; i++) {
if (in[i] == 'A') {
number_of_As += 1;
}
}
// If number_of_As == 0, you can just do a strdup here and return
// Because of 1st loop, i == strlen(in), no need to call strlen
long bytes = (i - number_of_As + (number_of_As * 4) + 1) * sizeof(char);
// Error check here
// Only 1 memeory allocation needed
*buffer = (char *)malloc(bytes);
// Simple copy loop
for (i = 0, j = 0; 0 != in[i]; i++) {
// If it's an A replace
if (in[i] == 'A') {
(*buffer)[j++] = 'B';
(*buffer)[j++] = 'C';
(*buffer)[j++] = 'D';
(*buffer)[j++] = 'E';
}
// Not an A, just copy
else {
(*buffer)[j++] = in[i];
}
}
// Null terminate
(*buffer)[j] = 0;
return j;
}

Related

Error passing by reference when making os

I am making an os and have booted into a 64 bit kernel made in c. I have made a print function which is working and am trying to make a function to convert hex values to string so I can print them. My code is causing boot loops, yet when I compile the exact same code to run normally in linux it works perfectly. The relevant code:
int logarithm(double value, int base, int* output) {
int i = 0;
while (value > 1) {
value /= base;
i++;
}
*output = i;
}
int power(int value, int power, int* output) {
if (power == 0) {
value = 1;
} else {
for (int i = 0; i < (power - 1); i++) {
value *= value;
}
}
*output = value;
}
void hexToStr(unsigned int hex, char** string) {
int hexLength = 0;
logarithm((double)hex, 16, &hexLength);
char output[hexLength];
output[hexLength] = 0;
int powerValue = 0;
for (int i = 0; i < hexLength; i++) {
power(16, i, &powerValue);
output[hexLength - i - 1] = (hex & (powerValue * 15)) / powerValue + '0';
}
*string = output;
}
If I change the hexToStr() function code to this (removing the need for logarithm() and power() functions by hardcoding values for the string), it works in both linux and my kernel:
void hexToStr(unsigned int hex, char** string) {
int hexLength = 10;
char output[hexLength];
output[hexLength] = 0;
int powerValue = 0;
for (int i = 0; i < hexLength; i++) {
output[hexLength - i - 1] = 'A';
}
*string = output;
}
Any suggestions as to why this would happen?
The presented code invokes undefined behavior. For example let's consider this function
void hexToStr(unsigned int hex, char** string) {
int hexLength = 10;
char output[hexLength];
output[hexLength] = 0;
int powerValue = 0;
for (int i = 0; i < hexLength; i++) {
output[hexLength - i - 1] = 'A';
}
*string = output;
}
In this assignment statement:
output[hexLength] = 0;
there is written data outside the array because the valid range of indices is [0, hexLength).
Or the function sets a pointer passed to the function by reference to the local array output that will not be alive after exiting the function. So the returned pointer will have an invalid value.
Another example the result value of the function power when the parameter value is equal to 3 and the parameter power is equal to 3 will be equal to 81 instead of 27 due to the assignment statement in this for loop.
for (int i = 0; i < (power - 1); i++) {
value *= value;
}
Moreover the function returns nothing though its return type is not void.
int power(int value, int power, int* output) {
Also this expression
(hex & (powerValue * 15)) / powerValue + '0'
does not make a sense.
Needed to enable SSE unit to work with floats and doubles. As well as change how values are passed back. Working code:
void log(float value, float base, uint64_t* output) {
uint64_t i = 0;
while (value >= 1) {
value /= base;
i++;
}
*output = i;
}
void pow(uint64_t value, uint64_t exponent, uint64_t* output) {
uint64_t result = 1;
for (uint64_t i = 0; i < exponent; i++) {
result = result * value;
}
*output = result;
}
void hexToStr(uint64_t hex, char* output) {
uint8_t hexLen = 16;
log((float)hex, (float)16, &hexLen);
char result[hexLen + 3];
result[0] = '0';
result[1] = 'x';
result[hexLen + 2] = 0;
uint64_t powerValue = 1;
for (uint8_t i = 0; i < hexLen; i++) {
pow(16, i, &powerValue);
result[hexLen - i + 1] = (hex & (uint64_t)(powerValue * (uint64_t)15)) / powerValue + '0';
}
for (uint8_t i = 0; i < hexLen + 3; i++) {
switch(result[i]) {
case ':':
result[i] = 'A';
break;
case ';':
result[i] = 'B';
break;
case '<':
result[i] = 'C';
break;
case '=':
result[i] = 'D';
break;
case '>':
result[i] = 'E';
break;
case '?':
result[i] = 'F';
break;
}
output[i] = result[i];
}
}

How can I change an array of string pointers in another function?

I have been trying to figure out how to modify an array of char pointers but no matter what I do there appears to be no change below are the three arrays I'm trying to change including the call to the function I'm using.
char*cm1[5];
char*cm2[5];
char*cm3[5];
setupCommands(&cm1,commands,file,0);
setupCommands(&cm2,commands,file,1);
setupCommands(&cm3,commands,file,2);
The code below is the function itself.I was thinking that maybe it involves a double pointer but if I try *cmd to change the array I get a segmentation fault.
void setupCommands(char **cmd[], char* commands[],char file[],int index){
char str1[255];
strcpy(str1,commands[index]);
char newString [5][255];
int j = 0;
int ctr = 0;
int i;
//printf("str1 %s\n" ,str1);
for(i = 0; i <= strlen(str1); i++){
if(str1[i] == ' '|| str1[i] =='\0'){
newString[ctr][j] = '\0';
ctr++;//next row
j=0;// for next word, init index to 0
}else{
newString[ctr][j]=str1[i];
j++;
}
}
for(i = 0; i < ctr; i++){
//printf(" test2 %s \n", newString[i]);
cmd[i] = newString[i];
//printf(" test2 %d %s \n", i,cmd[i]);
}
//printf("index %d", i);
cmd[i]= file;
cmd[i + 1] = NULL;
//execvp(cmd[0],cmd);
//cmd
}
There are a few issues with your code:
you are trying to return references to the local 'char newString [5][255]' when the function exits. In simple worlds - never return anything locally allocated on the stack. This is the reason you are getting the segmentation fault.
char **cmd[] must be declared char *cmd[] - even though you will get a warning from the compiler assignment from incompatible pointer type, the code would run and execute correctly(essentially **cmd[] would do the same work as *cmd[], even though it's not of correct type) if you didn't return references to the local object;
Easy and simple optimization is just to remove the array str1 and directly operate on the array commands.
Apart from this simple optimization I have changed your code to overcome the segmentation fault, by allocating on the heap, instead on stack(will live until the program terminates) the multidimensional array, and I also calculate it's size so I will know how much memory to allocate. Now it's safe to return references to it.
Note that more optimizations could be made, but for the sake of the simplicity this is the bare minimal for this code to work.
int setupCommands(char *cmd[], char *commands[], char file[], int index)
{
int j = 0;
int ctr = 0;
int i = 0;
int rows = 0;
int cols = 0;
char **newString = NULL;
while(commands[index][i])
{
if (commands[index][i] == ' ')
{
++rows;
}
++i;
}
++rows;
cols = strlen(commands[index]) + 1;
newString = malloc(rows * sizeof(*newString));
if (newString == NULL)
{
return -1;
}
for (i = 0; i < rows; ++i)
{
newString[i] = malloc(cols * sizeof(*newString));
if (newString[i] == NULL)
{
return -1;
}
}
for(i = 0; i <= strlen(commands[index]); i++){
if(commands[index][i] == ' '|| commands[index][i] =='\0'){
newString[ctr][j] = '\0';
ctr++;//next row
j=0;// for next word, init index to 0
}else{
newString[ctr][j]=commands[index][i];
j++;
}
}
for(i = 0; i < ctr; i++){
cmd[i] = newString[i];
}
cmd[i]= file;
cmd[i + 1] = NULL;
return 0;
}
First of all - being the three stars pointer programmer is not good :)
You assign it with pointer to the local variable which is not longer available after the function return
But if you still want the three stars pointers:
char **cm1;
char **cm2;
char **cm3;
setupCommands(&cm1,commands,file,0);
setupCommands(&cm2,commands,file,1);
setupCommands(&cm3,commands,file,2);
#define MAXWORD 256
int setupCommands(char ***cmd, const char *commands,const char *file,int index){
char str1[255];
strcpy(str1,commands[index]);
int j = 0;
int ctr = 0;
int i;
//printf("str1 %s\n" ,str1);
*cmd = malloc(sizeof(char *));
**cmd = malloc(MAXWORD);
if(!*cmd || !**cmd)
{
/* do spmething if mallocs failed*/
return -1;
}
for(i = 0; i <= strlen(str1); i++){
if(str1[i] == ' '|| str1[i] =='\0'){
(*cmd)[ctr][j] = '\0';
ctr++;//next row
*cmd = realloc((ctr + 1) * sizeof(int));
(*cmd)[ctr] = malloc(MAXWORD);
if(!*cmd || !*cmd[ctr])
{
/* do spmething if mallocs failed*/
return -1;
}
j=0;// for next word, init index to 0
}else{
(*cmd)[ctr][j]=str1[i];
j++;
}
}
*cmd = realloc(sizeof(char *) * ctr + 2)
(*cmd)[ctr - 2] = malloc(MAX);
if(!*cmd || !*cmd[ctr - 2])
{
/* do spmething if mallocs failed*/
return -1;
}
strcpy((*cmd)[ctr - 2], file);
(*cmd)[ctr - 1] = NULL;
return 0;
//execvp(cmd[0],cmd);
//cmd
}
you can improve many things (for example do not realloc every time but in the larger chunks) and I did not change anything in your code logic.

Freeing up memory with free function causing my program to crash

I could use some help with my program,
I wrote a program that is counting the number of anagrams in a sentence, for which I am using a malloc() function, you can see in my code **ArrPtr=malloc.
I use this to count the anagrams, after finishing it I want to continue to my second part of the program and I wish to free the memory with free(arrPtr);
and the program crashes (It didn't crash when I did not use the free option).
Here's my code,
void main()
{
char str[1001] = { 0 };
char temp[1001] = { 0 }, temp2;
char strB[1001] = { 0 };
int printf_i, counter, i, q, flag, j = 1, r = 0, m = 1, length = 0, root = 0, m1 = 0;
int max_analogy = 0, counter2 = 0, O, sum, sum2;
char **arrPtr;
int k = 0;
int **matrix;
printf("Please enter the sentence, and then press Enter:\n");
gets(str);
//bubble sort
strcpy_s(strB, 1001, str);
for (i = 0; i < strlen(strB); i = q + 2)
{
do
{
flag = 0;
for (q = i; strB[q + 1] != 32 && strB[q + 1] != 0; q++)
{
if (strB[q] > strB[q + 1])
{
// Swap
temp2 = strB[q];
strB[q] = strB[q + 1];
strB[q + 1] = temp2;
flag = 1;
}
}
} while (flag != 0);
}
counter = 1;
length = strlen(strB);
for (i = 0; strB[i] != 0; i++)
{
if (strB[i] == 32)
{
strB[i] = 0;
counter++;
}
}
arrPtr = (char*)malloc(sizeof(char)*counter);
arrPtr[0] = strB;
q = 1;
for (i = 0; i < length - 1; i++)
{
if (strB[i] == 0)
{
arrPtr[q] = &strB[i + 1];
q++;
}
}
counter2 = 0;
for (i = 0; i < counter; i++)
{
for (q = i + 1; q < counter; q++)
{
if (arrPtr[q] == 0 || arrPtr[i] == 0)
continue;
if (!strcmp(arrPtr[q], arrPtr[i]))
{
counter2++;
arrPtr[q] = 0;
}
}
if (max_analogy < counter2)
max_analogy = counter2;
counter2 = 0;
}
printf("The maximum number of anagram words in this sentence is %d.\n", max_analogy);
free(arrPtr);
}
arrPtr = (char*)malloc(sizeof(char)*counter);
is wrong fo many reason:
arrPtr is (char **).
cast using a C compiler is useless and dangerous.
you must allocate sizeof(char *)
reason 3 is the real reason of you problem: you are allocating counter bytes while you write counter*sizeof(char *) (most probably counter*8), so you are writing out of bounds of allocated memory corrupting malloc memory pool.
You can fix it using
arrPtr = malloc(sizeof(char *)*counter);

Hash function C

I am having trouble implementing my hash function for my hash table.
I want to hash my words such that A = 1, B = 2, C = 3, and so on. The position of the letter in the word is irrelevant, since we will consider permutations of the word. Moreover, the case of the letter will be irrelevant in this problem as well, so the value of a = the value of A = 1.
And for strings, abc = 1 + 2 + 3 = 6, bc = 2 + 3 = 5, etc.
And for cases where ab = 3 and aaa = 3, I have already had a way to handle that situation. Right now I just want to get the hash value.
The problem I am having right now is that aaa is giving me 1, and ab is giving me 2.
Below is my code:
int hash(char *word)
{
int h = 1;
int i, j;
char *A;
char *a;
// an array of 26 slots for 26 uppercase letters in the alphabet
A = (char *)malloc(26 * sizeof(char));
// an array of 26 slots for 26 lowercase letters in the alphabet
a = (char *)malloc(26 * sizeof(char));
for (i = 0; i < 26; i++) {
A[i] = (char)(i + 65); // fill the array from A to Z
a[i] = (char)(i + 97); // fill the array from a to z
}
for (i = 0; i < strlen(word); i++) {
//printf("HIT\n");
for (j = 0; j < 26; j++) {
// upper and lower case have the same hash value
if (word[i] == A[j] || word[i] == a[j]) {
h = h + j; // get the hash value of the word
//printf("HIT 2\n");
break;
}
}
}
printf("H: %d\n", h);
return h;
}
I think that changing
int h = 1;
to
int h = 0;
and
h = h + j;
to
h = h + j + 1;
will fix the issue.
The one other problem is that you forgot to free the malloced memory. Also, there is no need to cast the result of malloc(and family) in C.
This
for (i = 0; i < strlen(word); i++) {
will call strlen in every iteration of the loop. This will reduce the performance of your program. Use
int len = strlen(word);
for (i = 0; i < len; i++) {
instead, which is much faster as strlen isn't called in every iteration. Lastly, sizeof(char) is 1. So you can omit it.
change h=h+j to h=h+j+1
and h=1 to h=0.
Also you should free the allocated memory so include these lines just before return:
free(A);
free(a);
However I don't understand why so complicated code was written for such a simple task.
A much simpler code can be written:
int hash(char *word)
{
int sum=0;
while(*word != '\0')
{
if(*word >='A' && *word < 'A'+26)
sum=sum+(*word -'A' + 1);
else if(*word >='a' && *word < 'a'+26)
sum=sum+(*word -'a' + 1);
else
return -1;
word++;
}
return sum;
}
Multiple issues:
You still aren't freeing the arrays you allocated
Initial value of 1 for h makes no sense
You add the index to the hash. 'A' and 'a' are at index 0, so you're adding 0 in that case (so no matter how many 'a' s you give your code will return 1)
Why a dynamic array? You know the size, it isn't going to change. You could use
char A[26];
char a[26]; // you can also add initialisation, e.g. = {'a', 'b', ...
Why an array in the first place?
So, here is the quick fix, staying close to your code.
Taking all of the above into account, you could simplify to:
int hash(char const * string) {
int h = 0;
for (; *string; ++string) {
int index = tolower(*string) - 'a' + 1;
if ((index > 0) && (index < 27)) {
h += index;
}
}
return h;
}
Live
When only hashing words with non special characters, you need to handle ignored words in the caller somehow.
char hash(char const * string, int * h) {
*h = 0;
for (; *string; ++string) {
int index = tolower(*string) - 'a' + 1;
if ((index > 0) && (index < 27)) {
*h += index;
} else {
return 0;
}
}
return 1;
}
That way you can use the return value to test if the word should be ignored.

Segmentation fault on calling function more then once

running this function more then once will cause a Segmentation fault and i cannot figure out why. Im not looking for alternative ways to split a string.
SplitX will continue splitting for x ammount of delimiters (be it '|' or '\0') and return the x or the number of substrings it could make.
I should note i have just restarted coding in C after 3 years of easy JavaScript and PHP so i could be missing something obvious.
int splitX(char **array, char *string, int x) {
int y;
int z;
int index = 0;
int windex = 0;
for(y = 0; y < x; y++) {
z = index;
while(string[index] != '\0' && string[index] != '|') {
index++;
}
char **tempPtr = realloc(array, (y+1)*sizeof(char *));
if(tempPtr == NULL) {
free(array);
return -3;
}
array = tempPtr;
array[y] = malloc(sizeof(char) * (index - z + 1));
windex = 0;
for(; z < index; z++) {
array[y][windex] = string[z];
windex++;
}
array[y][windex] = '\0';
if(string[index] == '\0')
break;
index++;
}
return y+1;
}
int main() {
char **array;
int array_len = splitX(array, query, 2);
printf("%s %s %d\n", array[0], array[1], array_len);
while(array_len > 0) {
free(array[array_len-1]);
array_len--;
}
free(array);
array_len = splitX(array, "1|2\0", 2);
printf("%s %s %d\n", array[0], array[1], array_len);
while(array_len > 0) {
free(array[array_len-1]);
array_len--;
}
free(array);
}
char **array;
int array_len = splitX(array, query, 2);
This lets splitX() use the uninitialized array, which results in undefined behavior.
Furthermore, C has no pass-by-reference - when you write
array = tempPtr;
inside the function, that has no visible effect outside it.
Im not looking for alternative ways to split a string.
You should really be. Your current approach is at best non-idiomatic, but it also has some other mistakes (like returning y + 1 for some reason where y would do certainly, etc.).
You are also reinventing the wheel: for string and character searching, use strstr(), strchr() and strtok_r() from the C standard library; for duplicaitng a string, use strdup() instead of going through the string manually, etc., etc...
What else:
use size_t for sizes instead of int;
maintain const correctness by using const char * for input strings.
char **split(const char *s, size_t *sz)
{
char **r = NULL;
size_t n = 0, allocsz = 0;
const char *p = s, *t = p;
int end = 0;
do {
const char *tmp = strchr(p, '|');
if (tmp == NULL) {
p = p + strlen(p);
end = 1;
} else {
p = tmp;
}
if (++n > allocsz) {
if (allocsz == 0)
allocsz = 4;
else
allocsz <<= 1;
char **tmp = realloc(r, sizeof(*r) * allocsz);
if (!tmp) abort(); // or whatever, handle error
r = tmp;
}
r[n - 1] = malloc(p - t + 1);
memcpy(r[n - 1], t, p - t);
r[n - 1][p - t] = 0;
p++;
t = p;
} while (!end);
*sz = n;
return r;
}

Resources