I'm trying to do very basic examples to understand how void pointers work. Here's an example I've written for having a void* string and casting it to its "working" type and printing some aspects of it:
int main(int argc, char *argv[]) {
// Create a void pointer which "acts like" a string
void * string = "hello";
// "Cast" the string so it's easier to work with
char * string_cast = (char*) string;
// Print the string and a character in it
printf("The string is: %s\n", string_cast);
printf("The third character is: %c\n", string_cast[2]);
// How to now do something like:
// (1) void pointer_to_string_obj = ?
// (2) cast that pointer_to_string_obj to a normal string
// (3) print the string like it would normally be done
}
Could someone please show an example of manually creating a string pointer of type *(char**) and why that type would need to be created in the first place (why not just a normal char*?). I apologize if my question is broad, but basically I'm trying to figure out various void pointer types and where I'm at now in my very beginner understanding, it's a bit confusing, and so seeing a few examples would be very helpful.
So I thought up a kind of a good example of double void pointer (that is, void**). One way to cut down on double-free bugs is to always set pointers to NULL after freeing them.
We could do so like so (questionable style):
myprojectinclude.h:
/* must happen after any standard headers */
void freep(void **pointer);
#define free(p) error_call_freep_instead p /* so that free doesn't exist anymore */
freep.c:
#include <stdlib.h>
#include "myprojectinclude.h"
#undef free
void freep(void **p)
{
if (p) {
free(*p);
*p = NULL;
}
}
main.c:
#include <stdio.h>
#include <stdlib.h>
#include "myprojectinclude.h"
int main()
{
char *buffer = malloc(2048);
size_t buffer_size = 2048;
/* ... lots of code involving reading lines, etc. */
freep(&buffer);
/* buffer is guaranteed to be NULL here */
}
With this setup, double free is impossible. If we do
freep(&buffer);
freep(&buffer);
nothing goes wrong because buffer is NULL after the first call. (Note that passing NULL to free is safe; else we would add a NULL check like I had to do decades ago.)
Related
I am working with a bunch of strings for logging. I want to refactor my code and make a new struct that combines the char, its length and allocated size. The idea is to make my internal string operations smoother and the code nicer to read, whilst assigning each string its own max allocated memory to keep the usage to a minimum but prevent stack overflow. I made this simple example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char *str;
int size;
int max;
} Text;
void defText(Text *text, int max)
{
text->str=(char*) malloc(max * sizeof(char));
text->str="";
text->max=max;
}
int main() {
Text *a;
defText(a,50);
a->str="Test all you want";
printf("OUT: %s %zu %lu",a->str,strlen(a->str),sizeof(a->str));
return 0;
}
The function defText initializes and allocates memory. However, when I check the sizeof the char in my struct, I always get 8, no matter what I set in defText. Is this kind of struct handling strings and their properties together even possible? If so, what is wrong here?
There are several problems in your code, this is an example that cleans up these problems:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char *str;
// you could use size to keep track of the strlen. That's particularly
// desirable if you find yourself calling strlen "a lot", since that
// function recalculates the length every time it's called
int size;
int max;
} Text;
void defText(Text *text, int max)
{
// no need to cast the return of malloc. In fact, sizeof(char) is defined by
// the standard to be 1 so you could take that out also.
text->str=malloc(max * sizeof(char));
// `=` is not the proper way to write strings in C, you must use strcpy
// or something similar. It looks like here you're simply trying to
// create an empty string.
//text->str="";
// per #JohnBollinger's comment, the best thing to do here to create
// an empty string is simply set to the first byte to the NUL
// terminator.
text->str[0] = '\0';
text->max=max;
}
int main() {
Text a; // store this in automatic memory, now the object exists without having to malloc
defText(&a,50); // Use & to pass the address of a to defText
// as mentioned, this is not the proper way to write data to a string in
// C. What you've done here is create a memory leak and point a.str to
// the string literal "Test all you want". Use strcpy (or similar) to
// write that string into the data you actually malloc'ed (using the dot
// operator now since `a` is no longer a pointer)
//a->str="Test all you want";
strcpy(a.str, "Test all you want");
// a.str is a pointer, and will always be 8 bytes on your system no matter
// the size of the memory it points to
printf("OUT: %s %zu %zu",a.str,strlen(a.str),sizeof(a.str));
// clean up allocated memory. Since we're about to exit, there's
// really no need to do this here (the OS will reclaim all allocated
// memory when the process ends), but if you're writing a more
// involved, long-running program, you need to be sure to handle
// memory allocations and deallocations appropriately as needed
free(a.str);
return 0;
}
Demo
The
a->str
is pointer .
the correct answer is
sizeof(*(a->str))
This question already has answers here:
pass strings by reference in C
(8 answers)
Closed 7 years ago.
I'm trying to Initialize a string in Initialize then pass it to int main() for screen output, but it seems that the strings that are initialized have become corrupted.
Headers
#include<stdio.h>
#include<stdlib.h>
Initialize
void
Initialize(char* STRINGs)
{
STRINGs = malloc(sizeof(char)*5);
STRINGs = "hello" ;
printf("1: %s\n",STRING);
}
Main
int
main (char* STRINGs)
{
Initialize(STRINGs);
//The program stops working when it reaches this section
printf("2: %s",STRINGs);
return 0;
}
You can use this code to initialize the string variable
char * Initialize()
{
char* STRINGs="HELLO";
printf("1: %s\n",STRINGs);
return STRINGs;
}
int main ()
{
char *strings =Initialize();
//The program stops working when it reaches this section
printf("2: %s",strings);
return 0;
}
First, you have wrong prototype for int main (char* STRINGs), which must be either:
int main(), or
int main( int argc, char *argv[] )
How do I pass a string array from a function to main
As it stands, you can create a string inside your Initialize() then return a pointer to that string.
There are several issues in your Initialize() though.
Here's a suggestion to change:
char *
Initialize()
{
char *STRINGs = malloc(strlen("hello") + 1); // <-- malloc must include an additional space for the NULL terminator.
strcpy( STRINGs, "hello" ); // <-- NEVER use assignment for string type.
printf("1: %s\n",STRINGs);
return STRINGs;
}
Then your main() can be like this:
int main()
{
char *str = Initialize();
printf( "str = %s\n", str );
return 0;
}
NOTE: do not forget to add #include <string.h>
Here's an answer. First, when allocating memory for any variable, it must be freed or you'll get some nasty system errors at some point or at the very least, a memory leak.
In the int main(), the declaration should ideally be int main(int argc, char* argv[]).
I also recommend allocating at least one more byte of memory just in case you create a string and a function you use later on requires a null character appended to it.
I fixed your code to make it work at its bare minimum.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* Initialize(){
char* string = malloc(sizeof(char)*6);
strcpy(string,"hello");
printf("1: %s\n",string);
return string;
}
int main (int argc, char* argv[]){
char *strings=Initialize();
printf("2: %s\n",strings);
free(strings);
return 0;
}
For a shorter version of your code, I suggest this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char* argv[]){
char* strings=malloc(6);
strcpy(string,"hello");
printf("2: %s\n",strings);
free(strings);
return 0;
}
For the sake of understanding, let us suppose STRINGs of main function is a.
And STRINGs of initialize function is b.
At first, in main a is pointing to some unknown location say u. When you pass this to the initialize function then b also starts pointing to the location u.
But, after the allocation of memory, b starts pointing to some other memory that was allocated by malloc say m.
Now you change the contents of memory m by use of b. But a is still pointing to the unknown location u.
So both the pointers are now pointing towards two different memory locations. So when you print contents where b is pointing it works perfectly and then you printf contents of a which has no specific location or may be null.
So, because of this your problem came.
And also, there is another error in your program that is in the printf of initialize function, it has given a parameter STRING which is undeclared....make it STRINGs.
Hope you will like the explanation. Its a little bit tricky.
Thanks :-)
You can use:
void Initialize(char** STRING)
Instead:
void Initialize(char* STRINGs)
because you want to change the the address to which STRING points
Also you have wrong prototype of main
Try:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void Initialize(char** STRING)
{
*STRING = malloc(6);
strcpy(*STRING, "hello");
printf("1: %s\n",*STRING);
}
int main (int argc, char *argv[])
{
char* STRING;
Initialize(&STRING);
printf("2: %s\n",STRING);
free(STRING);
return 0;
}
So, I'm brand spanking new to C. C# does garbage collection for me, so i don't need to worry about this stuff usually. This is causing me a days worth of problems, and I'm not finding any real example code where passing references and pointers as arguments is clearly exlained.
I also understand that passing things by value is considered poor practice, but I can't even grasp the concept of passing and referencing things in the first place.
Stated Goal: set value of a type defined string in another function, without a typed function, or any return values.
Any elementary explanation of passing pointers and references functionally would be helpful. The "Programming in C" book says to do something like this:
swap(int *a, int *b){
//swap
}
//main
int a, b;
swap(&a,&b);
And if it could be done using some semblance of my code sample?
Thanks so much in advance!
Code:
#include <stdio.h>
//yes I'm aware that I need to set the array size
//to be larger than string length + 1 to account for "\0"
//this is a contrived, overly simplistic example for the sake
// of hopefully getting a very clear basic example
typedef char * string;
void func2(string *str){
str = "blah"
//currently, my code here does not change the value of str
//as declared in main
//have tried multiple different formats
//i.e. func2(&str)
//func2(str)
//func2(*str)
//etc
//*str in this context I thought should be a pointer to the value of str passed from func
//or perhaps str should be... not exactly sure what is going on and why
//this is so difficult
}
void func(string *str){
str = "blah blah";
//also trying
//*str = "blah"
//under the impression that this is now a char *** type? or char ** type?
//in my code, str may be passed to a func2(str);
//where it may be manipulated again
//it is my understanding that passing func2(&str) would
//pass in the address of a pointer, which I don't want
//or passing func2(*str) would pass a pointer to a pointer
// which i also don't want.
}
main(){
string str;
//pass location of str in memory
funct(&str);
//this code will print the str set in func, but not when modified in func2
printf("%s", str);
}
Making minimal modifications to your code, you might want something like this:
#include <stdio.h>
typedef char * string;
void func2(string *str){
*str = "blah";
}
void func1(string *str){
func2(str);
}
int main(){
string str;
func1(&str);
puts(str);
func2(&str);
puts(str);
return 0;
}
Compiled and tested okay.
This question already has an answer here:
Pointer losing its value + execv compilation warning
(1 answer)
Closed 7 years ago.
my original problem is that I want to write a function that can return me two values. I know that I can do it by passing the address of the two arguments to the function, and directly calculate their values inside that function. But when doing experiment, something weird happens. The value I got inside the function cannot survive to the main function:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void build(char *ch){
ch = malloc(30*sizeof(char));
strcpy(ch, "I am a good guy");
}
void main(){
char *cm;
build(cm);
printf("%s\n", cm);
}
The above program just prints out some garbage. So I want to know what's wrong here. Eventually, I want something like this parse(char **argv, char **cmd1, char **cmd2), which can parse out two commands for me from the original command argv. That would be great if anybody can explain a little bit. Thanks a lot.
build() take the pointer ch by value, i.e. a copy of the pointer is passed to the function. So any modifications you make to that value are lost when the function exits. Since you want your modification to the pointer to be visible in the caller's context, you need to pass a pointer to pointer.
void build(char **ch){
*ch = malloc(30*sizeof(char));
strcpy(*ch, "I am a good guy");
}
Also, you don't need to pass pointers to a function because you need to return multiple values. Another option is to create a struct that contains the values you wish to return as members, and then return an instance of said struct. I'd recommend this approach over the first if the values are related and it makes sense to package them together.
Here's a re-listing of your code after fixing bugs:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void build(char **ch){
*ch = malloc(30 * sizeof(char));
strcpy(*ch, "I am a good guy");
}
int main() { // main must return int
char *cm;
build(&cm); // pass pointer to pointer
printf("%s\n", cm);
free(cm); // free allocated memory
return 0; // main's return value, not required C99 onward
}
If you want to malloc inside the function, you need to pass the address to the outside pointer since ch inside the function is only a local variable, and changing it doesn't affect the outside cm variable
void build(char **ch){
*ch = malloc(30*sizeof(char));
strcpy(*ch, "I am a good guy");
}
void main(){
char *cm;
build(&cm);
printf("%s\n", cm);
}
But better don't malloc inside the function, instead just write what you want to the area pointed to by the pointer. This is the common way when you need to provide a buffer to get data in C. In this way users will have the choice to allocate memory their own, or just use a local buffer and don't need to free memory after that like you've just forgotten in your example
void build(char *ch){
strcpy(ch, "I am a good guy");
}
void main(){
char *cm1;
cm1 = malloc(30*sizeof(char));
build(cm1);
printf("%s\n", cm1);
char cm2[30];
build(cm2);
printf("%s\n", cm2);
free(cm1); // don't forget this
}
This is because in C, you cannot reassign the memory address of the pointer because it is passed by value.
If you really want to do this, you must pass the address of the pointer into the build function.
See: Passing pointer argument by reference under C?
I'm learning the concept of prototyping in C, however I'm struggling with the correct syntax. I'm writing a function to strip all non-alphbetic characters from a c-string
#include <stdio.h>
#include <string.h>
char[30] clean(char[30] );
int main()
{
char word[30] = "hello";
char cleanWord[30];
cleanWord = clean(word);
return 0;
}
char[30] clean(char word[30])
{
char cleanWord[30];
int i;
for(i=0;i<strlen(word);i++)
if ( isalpha(word[i]) )
cleanWord[i]=word[i];
cleanWord[i]='\0';
return cleanWord;
}
How do I correctly prototype the function? What are the other syntax errors that are preventing my program from compiling?
Your problem is not with function prototyping (aka forward declaration). You just can't return an array from a function in C. Nor can you assign to an array variable. You need to make a couple of changes to get things working. One option:
change char cleanWord[30] in main to be char * cleanWord.
change the signature of clean to char *clean(char word[30])
use malloc to allocate a destnation buffer inside clean
return a pointer to that new buffer
free the buffer in main
And another:
change the signature of clean to void clean(char word[30], char cleanWord[30])
operate on the passed-in pointer rather than a local array in clean
change the call in main to be clean(word, cleanWord).
As Carl Norum said, you can't return an array. Instead, what you tend to do is supply the output:
void clean( const char word[30], char cleanWord[30] )
{
}
And you should remove the locally-scoped array from that function.
You will find that the function does not work correctly, because you only have one iterator i. That means if a character is not an alpha, you will skip over a position in the output array. You will need a second iterator that is incremented only when you add a character to cleanWord.
A couple of notes (was a bit late with writing up an answer, seems I've been beaten to them by the others )
C cannot return local (stack) objects, if you want to return an array from a function you have to malloc it
Even if you declare an array argument as (char arr[30]), (char* arr) is just as valid as arrays decay to pointers when passed as arguments to functions. Also, you won't be able to get the size correctly of such arrays by using sizeof. Even though it's 30, on my machine it returns 4 for word in clean, which is the size of the pointer for it.
You are missing an include, isalpha is part of ctype.h
I've updated your code, hopefully I've guessed your intentions correctly:
#include <stdlib.h> /* for malloc and free */
#include <string.h> /* for strlen */
#include <ctype.h> /* for isalpha */
#include <stdio.h> /* for printf */
/* Function declaration */
char* clean(char word[30]);
/* your 'main()' would now look like this: */
int main()
{
char word[30] = "hel1lo1";
char* cleanWord;
cleanWord = clean(word);
printf("%s\n", cleanWord);
free(cleanWord);
return 0;
}
/* Function definition */
char* clean(char word[30])
{
char* cleanWord = malloc(30); /* allocating dynamically an array of 30 chars,
* no need to use sizeof here as char is
* guaranteed to be 1 by the standard
*/
unsigned int i, j = 0; /* let's fix the problem with non-alpha chars already pointed out */
for (i = 0; i < (strlen(word)); i++)
if (isalpha(word[i]))
cleanWord[j++] = word[i];
cleanWord[j] = '\0';
return cleanWord;
/* return a pointer to the malloc`ed array, don't forget to free it after you're done with it */
}