Storing chars into a string with a for loop? - c

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.

Related

How can I free memory and at the same time return a pointer?

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);
}
}

Function to append strings returning pointer/cast error

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);

C function for returning custom length char

Please be aware that I am new to C. I am coding a function that receives a number and returns a *char formed by '*' of the received length. i.e:
createHiddenName(6)//returns "******"
createHiddenName(4)//returns "****"
I've coded it like this, but it's not working:
char *createHiddenName(int length)
{
char *hidden[length];//
int i;
for (i = 0; i < length; i++) {
hidden[i] = '*';
}
return *hidden;
}
Any help would be highly appreciated. Thank you so much
Two major problems:
char *hidden[length];
This defines hidden as an array of pointers to char. It could be an array of strings, not a string itself.
Then you attempt to return a pointer to this array, but the array is a local variable that goes out of scope and will cease to exist once the function returns. Using the returned pointer will then lead to undefined behavior.
The simplest solution is to pass the buffer to be filled as an argument. Something like
char *createHiddenName(int length, char *hidden)
{
...
return hidden;
}
Of course remember to create a buffer big enough to hold the full string including the null terminator (which you don't add now).
You need to use dynamic memory allocation as below
char *createHiddenName(int length)
{
char *hidden = malloc((length+1) * sizeof(char));
if(hidden == NULL) {
return NULL;
}
int i;
for (i = 0; i < length; i++) {
hidden[i] = '*';
}
hidden[i] = '\0'; //Null terminated string
return hidden;
}
Make sure you need to free the memory after done with hidden variable.
char *ptr = createHiddenName(10);
//....
// Use ptr
//....
// done ? then free it
free(ptr);
ptr = NULL;
In your original approach, you have,
char *hidden[length]; // Why would you like to have an array of pointers?
return *hidden; // Wrong because unless 'malloc'ated, a pointer inside the function will not work after the return, Consider what happens if the function stack is cleared.
Instead you can follow the below approach.
#include<stdio.h>
#include<string.h>
char hidden_name[100];
// global char array for storing the value returned from function
char *createHiddenName(int length)
{
char temp[length+1];
int i;
for (i = 0; i < length; i++) {
temp[i] = '*';
}
temp[i]='\0'; // Null terminating temp
strncpy(hidden_name,temp,(size_t)(length+1));
//Remember temp perishes after function, so copy temp to hidden_name
return hidden_name;
}
int main(){
printf("Hidden Name : %s\n",createHiddenName(6));
return 0;
}

How to send 2D char pointer to a function for memory allocation?

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
void createDynamicArrayForChar(int dimension, char **ptr)
{
ptr = (char**)malloc(dimension*sizeof(char*));
for (int i = 0; i < dimension; i++)
{
ptr[i] = (char*)malloc(20 * sizeof(char));
ptr[i] = "value";
}
}
int main()
{
char **ptrArray;
createDynamicArrayForChar(5, ptrArray);
printf("%s", ptrArray[3]);
getchar(); getchar();
return 0;
}
It gives some errors when I try to compile this codes. How can I solve this problem? How to send 2D char pointer to a function in C?
Firstly, as per the present code, I see two issues.
You're passing ptrArray to the function and trying to allocate memory inside the function. Please be aware, C uses pass by value for function argument passing, so, if you want to allocate memory to ptrArray and expect that to be refeclted back to the caller, without returning, you'll be needing to pass a pointer to that `ptrArray.
in the code
ptr[i] = (char*)malloc(20 * sizeof(char));
ptr[i] = "value";
You're leaking memory. Once you've allocated memory using malloc(), you should use strcpy() to copy the data into the allocated memory.
That said, some advice:
Please see why not to cast the return value of malloc() and family in C.
sizeof(char) is guaranteed to be 1 in C. Using that as a multiplier is not required.
Always check the success of malloc() before using the returned pointer.
You probably need this (no error checking and not debugged code):
void createDynamicArrayForChar(int dimension, char ***ptr)
{
*ptr = (char**)malloc(dimension*sizeof(char*));
for (int i = 0; i < dimension; i++)
{
(*ptr)[i] = (char*)malloc(20 * sizeof(char));
strcpy((*ptr)[i],"value");
}
}
or
char **createDynamicArrayForChar(int dimension)
{
char **ptr = (char**)malloc(dimension*sizeof(char*));
for (int i = 0; i < dimension; i++)
{
ptr[i] = (char*)malloc(20 * sizeof(char));
strcpy(ptr[i],"value");
}
return ptr;
}
int main()
{
char **ptrArray;
ptrArray = createDynamicArrayForChar(5);
...
Read also Sourav Ghosh's answer.

Char * (pointer) function

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*.

Resources