Related
The compareStrings is going to compare two strings. The code below works fine when the void pointer is cast to char pointer.
int compareStrings(void *value1, void *value2) {
const char *str1, *str2;
str1 = (char *)value1;
str2 = (char *)value2;
return strcmp(str1, str2);
}
However, when I cast the type to pointer to pointer to a char, the code dumps segmentation fault error which I think, reasonably, it should not.
int compareStrings(void *value1, void *value2) {
const char **str1, **str2;
str1 = (char **)value1;
str2 = (char **)value2;
return strcmp(*str1, *str2);
}
Can anyone explain the problem with the second function?
UPDATE:
The complete code is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int compare(void *value1, void *value2);
int binarySearch(void **array, int size, void *value,
int(*compareFunc)(void *, void *));
int compareStrings(void *value1, void *value2);
int binarySearch(void **array, int size, void *value,
int(*compareFunc)(void *, void *)) {
int low, mid, high, compareResult;
low = 0;
high = size;
while (low < high) {
mid = low + ((high - low) / 2);
compareResult = (*compareFunc)(array[mid], value);
if (compareResult < 0) {
low = mid + 1;
} else {
high = mid;
}
}
return low;
}
int compareStrings(void *value1, void *value2) {
const char *str1, *str2;
str1 = (char *)value1;
str2 = (char *)value2;
return strcmp(str1, str2);
}
int main() {
int nElements, maxStringLen, index;
char **stringArray;
char *sToFind;
nElements = 10;
maxStringLen = 100;
sToFind = NULL;
stringArray = malloc(sizeof(char *) * nElements);
for (int i = 0; i < nElements; i++) {
stringArray[i] = malloc(sizeof(char) * maxStringLen);
sprintf(stringArray[i], "sample%d", i+1);
}
sToFind = "sample3";
index = binarySearch((void **)stringArray, nElements, sToFind, compareStrings);
if (index >= nElements) {
printf ("ERROR: value %s not found at index %d\n", sToFind, index);
}else{
printf("item found at index %d!\n", index);
}
for(int i = 0; i < nElements; i++) {
free(stringArray[i]);
}
free(stringArray);
return 0;
}
when I cast the type to pointer to pointer to a char, the code dumps
segmentation fault error which I think, reasonably, it should not.
When you cast the pointer to pointer that operation does not affect the casted pointer. It still points to same memory.
This is demonstrated by printout 3.
1. Original string addresses:
Address of str1= 0x55bc799fea65
Address of str2= 0x55bc799fea6a
3. The addresses after casting `(char **)` do not change:
Address of (char **)value1= 0x55bc799fea65
Address of (char **)value2= 0x55bc799fea6a
Casting is not & or * operation!
When you do dereferencing by * that operation dereferences the value of the original pointer.
The result is not what you want:
4.
Address of *(char **)value1= 0x343332 00 34 33 32 31
Address of *(char **)value2= 0x31 00 35 34 33 32
These are not the addresses as you expected but the values of the strings.
Those values are not the valid addresses!
When you try to use them as the string addresses you will get segmentation fault in the strcmp function.
Take a look at the demo program:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void print_addresses(char *nr, char *d1, void *a1, char *d2, void *a2)
{
printf("%s.\nAddress of %s= %p\nAddress of %s= %p\n\n",nr, d1, a1, d2, a2);
}
int compareStrings1 (void *value1, void *value2)
{
char *str1, *str2;
str1 = (char *) value1;
str2 = (char *) value2;
//2.
print_addresses("2", "str1", str1, "str2", str2);
return strcmp(str1, str2);
}
int compareStrings2(void *value1, void *value2) {
char **str1, **str2;
char **s1, **s2;
str1 = (char **)value1; // warning: assignment from incompatible pointer type
str2 = (char **)value2; // warning: assignment from incompatible pointer type
//3. Addresses after casting `(char **)` do not change:
print_addresses( "3", " (char **)value1", str1, " (char **)value2", str2); // str1,str2 are still pointing to the original strings!
//---------------------------------------------------------------------------------------------
print_addresses( "4", "*(char **)value1", *str1, "*(char **)value2", *str2); // '*' this dereferences the address to the value of the first character
printf("(*str1)= %c\n", *str1); //'*' this dereferences the address to the value of the first character
printf("(*str2)= %c\n\n", *str2); //'*' this dereferences the address to the value of the first character
// Now:
s1 = (char **) &value1; // '&'' gives us pointer to pointer
s2 = (char **) &value2; // '&'' gives us pointer to pointer
//5.
print_addresses( "5", " (char **) & value1" , s1, " (char **) & value2", s2); // pointer to pointer address
//6.
print_addresses( "6", "*(char **) & value1", *s1, "*(char **) & value2", *s2); // dereferencing pointer to pointer
return strcmp(*s1, *s2); // OK!
}
int main()
{
char *str1 = "1234";
char *str2 = "2345"; // 5 bytes
//1. Original string addresses:
print_addresses("1", "str1", str1, "str2", str2);
int res1 = compareStrings1(str1, str2);
int res2 = compareStrings2(str1, str2);
return 0;
}
Output:
1.
Address of str1= 0x55bc799fea65
Address of str2= 0x55bc799fea6a
2.
Address of str1= 0x55bc799fea65
Address of str2= 0x55bc799fea6a
3.
Address of (char **)value1= 0x55bc799fea65
Address of (char **)value2= 0x55bc799fea6a
4.
Address of *(char **)value1= 0x3433320034333231
Address of *(char **)value2= 0x310035343332
(*str1)= 1
(*str2)= 2
5.
Address of (char **) & value1= 0x7ffd061f56b8
Address of (char **) & value2= 0x7ffd061f56b0
6.
Address of *(char **) & value1= 0x55bc799fea65
Address of *(char **) & value2= 0x55bc799fea6a
I hope it helps.
The problem is that your are casting a pointer and not transforming it into a pointer to a pointer.
The cast (char **) just change the type of the following expression, it do not transform it. So the original and the resulting pointer are still the same pointer (they point the same place in memory), just the type is different. So both points to a string. But with your cast you lie to the compiler: you are telling him that you know what you are doing, and that the pointer point to a pointer to a string.
So you get a segmentation fault: the pointer point to a text and not to a pointer to a text: you are deferencing a string and oops.
You should have written:
str1 = (char **)&value1;
Note: your const char * is probably wrong. You are saying that the string is constant (and only the first one), not that the variable is constant (which should be written char * const).
I am trying to take input from a user and I don't the exact length of input so therefore I am using malloc and I am splitting char by space between them and just need to print an array but I am getting warning i.e assignment makes integer from pointer without a cast on the following line:
array[i++] = p;
and my whole program is as follows:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main ()
{
char buf[] ="abc qwe ccd";
int i;
char *p;
char *array=malloc(sizeof(char));
i = 0;
p = strtok (buf," ");
while (p != NULL)
{
array[i++] = p;
p = strtok (NULL, " ");
}
for (i=0;i<3; ++i)
printf("%s\n", array[i]);
return 0;
}
Can anyone please tell me what is wrong with my code.
Thank you.
The following assignment is not right.
array[i++] = p;
array[i++] evaluates to type char. p is of type char*.
That's what the compiler is complaining about.
Judging by the way you are using array, it needs to be of type char**.
char **array = malloc(sizeof(*array)*20); // Make it large enough for your needs.
I guess you wanted to create array of pointers to char instead of array of char.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (void)
{
char buf[] ="abc qwe ccd";
int i;
char *p;
/* change type of array from char* to char** */
char **array=malloc(sizeof(char*) * sizeof(buf)); /* allocate enough memory */
i = 0;
p = strtok (buf," ");
while (p != NULL)
{
array[i++] = p;
p = strtok (NULL, " ");
}
for (i=0;i<3; ++i)
printf("%s\n", array[i]);
free(array); /* it is good to free whatever you allocated */
return 0;
}
I have a function to update an unsigned char* and cannot find where my bug is. I'm not sure if I need to allocate memory, or if I am pointing to the wrong memory space somewhere. I tried to follow a similar structure as posted here, but have not had success with an unsigned char.
My code so far:
#include <stdio.h>
void changeArray(unsigned char **arr)
{
unsigned char ptr[3] = {100, 101, 102};
*arr = ptr;
printf("%d\n", **(arr+0)); // This prints out the correct value of 100
}
int main(int argc, const char* argv[])
{
int i = 0;
unsigned char *blah;
unsigned char ptr2[3] = {103, 104, 105};
blah = ptr2;
printf("Blah is: \n");
for (i = 0; i < 3; i++) {
printf("%d,",*(blah+i)); //This prints out 103,104,105
}
changeArray(&blah);
printf("Blah is now: \n");
for (i = 0; i < 3; i++) {
printf("%d,", *(blah +i)); //This prints out 0,0,0
}
return 0;
}
Any help in determining how to properly access the values set in the changeArray() function would be greatly appreciated.
With this *arr = ptr; you are storing a pointer to a variable with automatic storage duration. The behaviour undefined.
You can dynamically allocate and return a pointer that way:
void changeArray(unsigned char **arr)
{
unsigned char ptr[3] = {100, 101, 102};
unsigned char *p = malloc(sizeof ptr);
memcpy(p, ptr, sizeof ptr);
*arr = p;
printf("%d\n", **(arr+0)); // This prints out the correct value of 100
}
You should also do error checking if malloc failed and remember to free the allocated memory after use in main.
The problem here is, ptr is local to changeArray() function. So once the function finishes execution, there is no existance of ptr. Hence, once you assign ptr to *arr
*arr = ptr;
and changeArray() execution gets over, accessing blah in main() now will invoke undefined behaviour.
FWIW, you don't need to pass the address of blah, you don't need a pointer-to-pointer at all. blah is already a pointer, which you can pass to changeArray() to alter the contents of the memory area it points to. You can do something like
void changeArray(unsigned char *arr)
{
for (int i = 0; i < 3; i ++)
arr[i] = 100+i;
}
and call it like
changeArray(blah);
There's a function. It is add_lexem and adds an element (char *) in the end of specified array and. If no memory left, it allocates some extra memory (100 * sizeof(char *)). That function causes segfault, which is the problem.
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
void add_lexem(char **lexems, int *lexemsc, int *lexem_n, const char *lexem)
{
if (*lexem_n >= *lexemsc) {
lexems = realloc(lexems, sizeof(char *) * (*lexemsc + 100));
*lexemsc += 100;
}
char *for_adding = malloc(sizeof(char) * strlen(lexem));
strcpy(for_adding, lexem);
lexems[*lexem_n] = for_adding;
(*lexem_n)++;
}
int main(void)
{
char **D = malloc(sizeof(char *) * 2);
int lexemsc = 2;
int lexem_n = 0;
add_lexem(D, &lexemsc, &lexem_n, "MEOW");
printf("%s\n", D[0]);
add_lexem(D, &lexemsc, &lexem_n, "BARK");
printf("%s\n", D[1]);
// in this place lexem_n becomes equal lexemsc
add_lexem(D, &lexemsc, &lexem_n, "KWARK");
printf("%s\n", D[2]);
return 0;
}
The output must be
MEOW
BARK
KWARK
but it is
MEOW
BARK
Segmentation fault (core dumped)
You're passing your lexeme parameter by value, when it should be by address:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
// removed unused void ccat(char *str, char c)
void add_lexem(char ***lexems, int *lexemsc, int *lexem_n, const char *lexem)
{
if (*lexem_n >= *lexemsc) {
*lexems = realloc(*lexems, sizeof(char *) * (*lexemsc + 100));
*lexemsc += 100;
}
char *for_adding = malloc(sizeof(char) * strlen(lexem)+1);
strcpy(for_adding, lexem);
(*lexems)[*lexem_n] = for_adding;
(*lexem_n)++;
}
int main(void)
{
char **D = malloc(sizeof(char *) * 2);
int lexemsc = 2;
int lexem_n = 0;
add_lexem(&D, &lexemsc, &lexem_n, "MEOW");
printf("%s\n", D[0]);
add_lexem(&D, &lexemsc, &lexem_n, "BARK");
printf("%s\n", D[1]);
// in this place lexem_n becomes equal lexemsc
add_lexem(&D, &lexemsc, &lexem_n, "KWARK");
printf("%s\n", D[2]);
return 0;
}
Output
MEOW
BARK
KWARK
Note: Triple indirection (i.e. a 3-start-programming) is not something to enter into lightly, though it actually fits what you appear to be trying to do here. Read the above code carefully and make sure you understand how it works.
Edit: added terminator space for added string. (don't know why I missed it, since it was what everyone else seemed to be catching on first-review, duh).
Note: See #wildplasser's answer to this question. Honestly it is the best way to do this, as it tightens the relationship between the string pointer array and the magnitude of said-same. If it is possible to retool your code to use that model, you should do so, and in-so-doing select that answer as the the "correct" solution.
Alternative to avoid the three-star-programming: put everything you need inside a struct:
struct wordbag {
size_t size;
size_t used;
char **bag;
};
void add_lexem(struct wordbag *wb, const char *lexem)
{
if (wb->used >= wb->size) {
wb->bag = realloc(wb->bag, (wb->size+100) * sizeof *wb->bag );
wb->size += 100;
}
wb->bag[wb->used++] = strdup(lexem);
}
The main problem is that you are passing D to the function by value: the assignment
lexems = realloc(...);
has no effect on D. In cases when realloc performs reallocation, D becomes a dangling pointer, so dereferencing it becomes undefined behavior.
You need to pass D by pointer in the same way that you pass lexemsc and &lexem_n, so that the realloc's effect would be visible inside the main function as well.
In addition, your add_lexem does not allocate enough memory for the string being copied: strlen does not count the null terminator, so these two lines
char *for_adding = malloc(sizeof(char) * strlen(lexem));
strcpy(for_adding, lexem);
write '\0' one byte past the allocated space.
The problem may come from :
char *for_adding = malloc(sizeof(char) * strlen(lexem));
strcpy(for_adding, lexem);
try char *for_adding = malloc(sizeof(char) * (strlen(lexem)+1)); to leave some space for the '\0 character.
Edit : and #WhozCraig seems to be right !
Bye,
I keep getting segmentation faults on this code, I'm learning C at the moment.. Can anyone help me out?
Error location:
char *m;
char *as = concat("helloworld", buf);
*m = sha1(as); <<<<<< as
printf("%s\n", m);
free(as);
The concat function (not mine, used for joining 2 strings):
char* concat(char *s1, char *s2)
{
size_t len1 = strlen(s1);
size_t len2 = strlen(s2);
char *result = malloc(len1+len2+1);//+1 for the zero-terminator
//in real code you would check for errors in malloc here
memcpy(result, s1, len1);
memcpy(result+len1, s2, len2+1);//+1 to copy the null-terminator
return result;
}
The sha1 function:
char *sha1( char *val ){
int msg_length = strlen( val );
int hash_length = gcry_md_get_algo_dlen( GCRY_MD_SHA1 );
unsigned char hash[ hash_length ];
char *out = (char *) malloc( sizeof(char) * ((hash_length*2)+1) );
char *p = out;
gcry_md_hash_buffer( GCRY_MD_SHA1, hash, val, msg_length );
int i;
for ( i = 0; i < hash_length; i++, p += 2 ) {
snprintf ( p, 3, "%02x", hash[i] );
}
return out;
}
Since I'm asking, what do they mean with:
//in real code you would check for errors in malloc here
Thanks in advance
sha1() returns char *, so you need to change *m = sha1(as); to m = sha(as);. *m is of type char, not char *.
change *m = sha1(as); to m = sha1(as);. *m is a char value not a char *.
Now second question:
in real code you would check for errors in malloc here
is all about error handling where you need to check returned pointer from malloc against NULL.
m = sha1(as);
*m dereferences the pointer, it means the character under the pointer.
As for malloc, if it cannot allocate memory if will return a NULL pointer. You should check for that.
The problem was in *m:
char *m = sha1("helloworld"); < OK
*m = sha1("helloworld"); < fail