I need to pass in a char * in a function and have it set to a cstring value. I can properly set it as a string in the function, but it doesn't seem to print out correctly in the function that called the char * function in the first place.
int l2_read(char *chunk,int length)
{
chunk = malloc( sizeof(char) * length);
int i;
for(i = 0; i < length; i++){
char c;
if(read(&c) < 0) return (-1); // this gets a single character
chunk[i] = c;
}
printf("%s",chunk); // this prints fine
return 1;
}
// main
char *string;
int value = l2_read(string,16);
printf("%s",chunk); // prints wrong
In C, everything is passed by value. A general rule to remember is, you can't change the value of a parameter passed to a function. If you want to pass something that needs to change, you need to pass a pointer to it.
So, in your function, you want to change chunk. chunk is char *. To be able to change the value of the char *, you need to pass a pointer to that, i.e., char **.
int l2_read(char **chunkp, int length)
{
int i;
*chunkp = malloc(length * sizeof **chunkp);
if (*chunkp == NULL) {
return -2;
}
for(i = 0; i < length; i++) {
char c;
if (read(&c) < 0) return -1;
(*chunkp)[i] = c;
}
printf("%s", *chunkp);
return 1;
}
and then in main():
char *string;
int value = l2_read(&string, 16);
if (value == 1) {
printf("%s", string); /* corrected typo */
free(string); /* caller has to call free() */
} else if (value == -2) {
/* malloc failed, handle error */
} else {
/* read failed */
free(string);
}
Pass-by-value in C is the reason why strtol(), strtod(), etc., need char **endptr parameter instead of char *endptr—they want to be able to set the char * value to the address of the first invalid char, and the only way they can affect a char * in the caller is to receive a pointer to it, i.e., receive a char *. Similarly, in your function, you want to be able to change a char * value, which means you need a pointer to a char *.
Hope that helps.
I just re-read your question.
You seem to have been hit by the pass by value, even if it is a pointer, problem. Also, is chunk null terminated?
You have to pass a pointer to a pointer.
int l2_read(char **chunk,int length)
{
*chunk = malloc( sizeof(char) * length);
int i;
for(i = 0; i < length; i++)
{
char c;
if (read(&c) < 0) return (-1);
(*chunk)[i] = c;
}
printf("%s",*chunk);
return 1;
}
char *string;
int value = l2_read(&string,16);
printf("%s",string);
I totally agree with the answer posted above. You are essentially modifying the value of pointer so you need to pass the reference of pointer. use char ** instead of char*.
Related
I have these functions
char *hash(char *stringa, char *tipohash) {
if (strcmp(tipohash, "md5") == 0) {
stringa = md5(stringa);
}
return stringa;
}
char *md5(char *stringa) {
unsigned char risultato[MD5_DIGEST_LENGTH];
int i;
char *hashfinale = malloc(sizeof(char) * MD5_DIGEST_LENGTH * 2);
MD5((const unsigned char *)stringa, strlen(stringa), risultato);
for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
sprintf(hashfinale + 2 * i, "%02x", risultato[i]);
}
return (char *)hashfinale;
}
How I can return (char *)hashfinale doing the free without losing the value of the string?
This is the caller
char *hashlinea = hash(stringa, hashType);
There are basically two ways to solve the problem, and none of them involves your code calling free.
The first way is to just do nothing different from now, except to add documentation so the user of your hash function knows that the code must call free on the returned pointer:
// This is the code using your function
char *hashlinea = hash(stringa,hashType);
// Some code using hashlinea
free(hashlinea);
The second way is to pass a pointer to an existing array, and your code use that array instead of allocating it using malloc:
char hashlinea[MD5_DIGEST_LENGTH*2];
hash(stringa, hashType, hashlinea);
For this your hash function needs to pass on the third argument to the md5 function, which should use it instead of allocating memory:
char *md5(char *stringa, char *hashfinale){
unsigned char risultato[MD5_DIGEST_LENGTH];
int i;
// No memory allocation here
MD5((const unsigned char *)stringa, strlen(stringa), risultato);
for(i = 0; i < MD5_DIGEST_LENGTH; i++) {
sprintf(hashfinale + 2*i,"%02x",risultato[i]);
}
return hashfinale;
}
It is not possible. IMO it is better to pass the pointer to the buffer. The caller will be responsible for the memory management
char *md5(char *stringa, char *hashfinale){
...
}
There is a problem in your md5 function: the size allocated for the MD5 hash must be one byte longer for the null terminator:
char *hashfinale = malloc(sizeof(char) * (MD5_DIGEST_LENGTH * 2 + 1));
Note that in C (and C++) sizeof(char) is 1 by definition, so you could just write:
char *hashfinale = malloc(MD5_DIGEST_LENGTH * 2 + 1);
Regarding your question, hash returns either its argument or an allocated object. This is a problem for memory management, as yo may not know later in the program if the return value must be freed or not. Passing the destination array for the hash string is a better alternative, otherwise you should duplicate the string so the return value of hash can be unconditionally freed:
char *md5(const char *stringa) {
unsigned char risultato[MD5_DIGEST_LENGTH];
int i;
char *hashfinale = malloc(MD5_DIGEST_LENGTH * 2 + 1);
MD5((const unsigned char *)stringa, strlen(stringa), risultato);
for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
sprintf(hashfinale + 2 * i, "%02x", risultato[i]);
}
return hashfinale;
}
// always free the return value
char *hash(const char *stringa, const char *tipohash) {
if (!strcmp(tipohash, "md5")) {
return md5(stringa);
} else {
return strdup(stringa);
}
}
I'm trying to create a function that takes two input strings, dest and src, and appends the src string to the dest string.
Below is the current function I have. However, when I try to use it, I
get an error stating "returning 'char' from a function without a cast." I understand that my error involves the return statement and how I'm using it as a pointer, but I'm unsure how to fix it.
char* strcat(char dest[], char src[]) {
int destL = lenstr(dest);
int srcL = lenstr(src);
char result[destL + srcL];
int i;
for(i = 0; i < destL; i++){
result[i] = dest[i];
}
for(i = destL; i < destL+srcL; i++){
result[i] = src[i-destL];
}
return *result;
}
The lenstr function is:
int lenstr(char* s) {
int len = 0;
while(s[len++] != '\0');
return len-1;
}
You cannot return a locally declared array. Well you can, but the data may be overwritten at any time since it is no longer valid.
What you need to do is something like this:
char* strcat(char dest[], char src[]) {
char * result = malloc((lenstr(dest)+lenstr(src)+1) * sizeof *result);
// Code to copy data
return result;
}
Note that +1 is important to make room for the \0 terminator.
However, when I try to use it, I get an error stating "returning 'char' from a function without a cast."
This error simply indicates that your return value doesn't match the function declaration. In your function declaration, you have mentioned that it returns a char *. However, in your actual return statement, you are returning *result which is a dereferenced char pointer i.e. a char.
The second problem in your code is that you are returning an array from the function. Memory allocated using an array in a method becomes unavailable to the caller method. You need to create memory on heap and return a pointer to it and then let the caller free up the memory after usage.
Checkout the following working code:
char* strcat1(char dest[], char src[]) {
int destL = lenstr(dest);
int srcL = lenstr(src);
char * result = malloc(sizeof(char) * (destL + srcL));
int i;
for(i = 0; i < destL; i++){
result[i] = dest[i];
}
for(i = destL; i < destL+srcL; i++){
result[i] = src[i-destL];
}
return result;
}
Please make sure the caller frees up the result as shown below:
char * result = strcat1("hi", "ho");
printf(result);
free(result);
Say for example I have a function called from main that returns a pointer:
EDIT
: I was a little unclear, sorry! Let's say I used a scanf in the main() and then I passed this into the function, and I wanted to copy the argument into a new pointer then return that one.
main(void)
{
char *word = malloc(50);
scanf("%s", word);
printf("%s", function(word));
}
char *function(char *array)
{
char *a = malloc(50);
while (*array)
{
*a = *array;
a++;
array++;
}
return a;
}
In this case, if I tried to return the pointer array to main, the pointer would be pointing to the memory location 1 space past where my values are held.
How would I make so I can return the pointer to the first value again?
Thanks!
The best way is to not increment your pointers at all:
char *function(char *array)
{
const size_t maxLength = 49;
char * a = malloc(maxLength + 1);
if ( !a ) {
perror("couldn't allocate memory");
exit(EXIT_FAILURE);
}
size_t i;
for ( i = 0; array[i] && i < maxLength; ++i ) {
a[i] = array[i];
}
a[i] = '\0';
return a;
}
Your original code does not null-terminate a, yet you pass it to printf() as if it's a string. Also, you're leaking memory, since you don't store the pointer you're returning, so you can never free() it.
The basic approach is to use a temporary variable to hold the pointer value you want to keep.
Assuming the only one you care about in your example is a.
char *function(char *array)
{
char *a, *t;
t = a = malloc(50);
while (*array)
{
*t = *array;
++t;
++array;
}
*t = '\0'; /* since the caller passes returned pointer to printf() */
return a; /* a unchanged, so return it */
}
Note that the above will have undefined behaviour if strlen(array) >= 50.
In your example, array is passed by value, so changes to it (repeated incrementing) do not propagate to the caller - there is no need to reset array back to its original value.
The best way would be to not use the parameter to the function, but a copy of it inside the function.
char* pTmp = array;
Also it's better to do ++pTmp rather than array++ because for non-POD types it can be quicker.
I have this function, bits_show, which prints to stdout a 2-3 bit long code.
void bits_show(bits *a)
{
int i;
for (i = 0; i < a->next; i++)
putchar(a->bits[i]);
}
where bits:
struct bits {
int capacity;
int next;
char *bits;
};
I am trying to write a function, char* bits_char(bits a) that captures these characters and collects them into a single char file.
This is what I have so far, but it keeps spitting errors:
char* bits_char(bits *a)
{
char* str = (char*) malloc( sizeof(a->next * char));
int i;
for (i=0; i<a->next; i++){
str[i] = (a->bits[i]);
}
return str;
}
"bits.c: In function ‘bits_char’:
bits.c:33: error: variable-sized object may not be initialized
bits.c:37: warning: function returns address of local variable"
This is wrong:
sizeof(a->next * char)
I presume you meant to write:
a->next * sizeof(char)
But since sizeof(char) equals 1 by definition you would simply omit that.
But even that is wrong since you need to allow space for the null terminator which your code does not currently write. The allocation needs to be:
malloc(a->next+1)
And add the null-terminator like this:
str[a->next] = 0;
All in all, the finished product is as so:
char* bits_char(bits *a)
{
char* str = malloc(a->next+1);
int i;
for (i=0; i<a->next; i++){
str[i] = (a->bits[i]);
}
str[a->next] = 0;
return str;
}
I removed the cast of the return value of malloc which is not needed in C.
And you should also ensure that you check the return value of malloc for a failed allocation. It will return the null pointer if it fails. I've not shown how to do that because I don't know your error handling policy.
In C, how can I create a function which returns a string array? Or a multidimensional char array?
For example, I want to return an array char paths[20][20] created in a function.
My latest try is
char **GetEnv()
{
int fd;
char buf[1];
char *paths[30];
fd = open("filename" , O_RDONLY);
int n=0;
int c=0;
int f=0;
char tmp[64];
while((ret = read(fd,buf,1))>0)
{
if(f==1)
{
while(buf[0]!=':')
{
tmp[c]=buf[0];
c++;
}
strcpy(paths[n],tmp);
n++;
c=0;
}
if(buf[0] == '=')
f=1;
}
close(fd);
return **paths; //warning: return makes pointer from integer without a cast
//return (char**)paths; warning: function returns address of local variable
}
I tried various 'settings' but each gives some kind of error.
I don't know how C works
You can't safely return a stack-allocated array (using the array[20][20] syntax).
You should create a dynamic array using malloc:
char **array = malloc(20 * sizeof(char *));
int i;
for(i=0; i != 20; ++i) {
array[i] = malloc(20 * sizeof(char));
}
Then returning array works
You should just return array (return array;). the ** after declaration are used for dereferencing.
Also, make sure the the memory for this array is allocated on the heap (using malloc or simillar function)