Proper use of Char** - c

I am new to C and came across a Char**, for example in the getline function. I have found several topics regarding this type but none of it explained how to actually use it. I understood the differences between Char[], Char* and Char**, but how can I access the content stored in a Char**?
Could someone explain that to me? Thanks in advance!! :)
So, for example i am trying to use the getline function to extract single lines from a file and to store them:
FILE *fp = fopen(myfile,"r");
size_t fsize;
char **string;
ssize_t bytes_read =0;
while ((bytes_read = getline(string, &fsize, fp))>0) {
// How to handle the content of string now? Is every line from the File stored in the Char** now?
}

Almost always when a function asks for a char** or a ** in general, you're expected to give it the address of a pointer variable. In this case the address of a char*. The address of operator is &, thus you should call getline like this:
char *string = NULL;
size_t size = 0;
while ((bytes_read = getline(&string, &fsize, fp))>0) {
// use string here...
}
free(string);
There are of course exceptions to the rule of ** functions wanting an address of, but getline isn't one of them.

In the case of getline it requires the memory address at which to store the memory address of the first character in the line you've read.
I.e. it needs a pointer to a pointer or a char**.
Your string will be stored in *string.
Of course you can get this information from the documentation :).

Related

Is there a way to safely collect the data from a returned char*?

I am working on a project for fun to learn C programming, and in Java, I know that I can just obtain a String from a method through a simple return statement. However, in C, I believe it is returning the address of the pointer or garbage data. Here is some basic code:
// In Main Method
char *words = getWords();
// ...
// In getWords
char *getWords() {
char *input; //Well-formatted input.
// Filler code that collects data through file or text entry with 256 max char.
char str[256];
scan("%s", str);
input = str;
return input;
}
You need to pass the pointer as an argument and store the data there itself. Declaring local pointer and returning it is not a good way of doing it. It may lead to dangling pointer.
https://www.geeksforgeeks.org/dangling-void-null-wild-pointers/
After further review, I have discovered that this is the problem:
char str[256];
Should be static:
static char str[256];
Now it returns the correct inputted string.

correct way to filter execve environment

I'm trying to write a LD_PRELOADable library that prevents processes from removing itself from this variable (to make sure children inherit it).
So far I sucessfully wrapped putenv,setenv and clearenv, but execve gives me issues.
My code so far:
int (*real_execve)(const char *filename, char *const argv[], char *const envp[]);
int execve(const char *filename, char *const argv[], char *const envp[]){
real_execve = dlsym(RTLD_NEXT,"execve");
char *path = getenv("LD_PRELOAD");
fprintf(stderr, "INTERCEPTED execve, env:\n");
int i;
for(i=0;envp[i]!=NULL;i++);
char *nenvp[i+1];
nenvp[i]=NULL;
for(i=0;envp[i]!=NULL;i++){
char *string = envp[i];
char *buf = malloc((strlen(string)+1)*sizeof(char));
strcpy(buf,string);
char *name = strtok(buf,"=");
char *value = strtok(NULL,"=");
if(0==strcmp(name,"LD_PRELOAD")){
fprintf(stderr," FIXING '%s'\n",string);
char * nstring = malloc((strlen(name)+strlen(path)+strlen(value)+3)*sizeof(char));
strcpy(nstring,name);
strcat(nstring,"=");
strcat(nstring,path);
strcat(nstring,":");
strcat(nstring,value);
nenvp[i]=nstring;
fprintf(stderr," TO '%s'\n",nenvp[i]);
free(string);
}else{
nenvp[i]=envp[i];
fprintf(stderr," LEFT '%s'\n",nenvp[i]);
}
free(buf);
}
fprintf(stderr, " CALLING %s\n", filename);
return real_execve(filename,argv,nenvp);
}
I'm encountering 2 issues:
it logs things like:
FIXING 'LD_PRELOAD=/usr/$LIB/libstdc++.so.6 /usr/$LIB/libgcc_s.so.1 /usr/$LIB/libxcb.so.1'
TO 'LD_PRELOAD=/usr/$LIB/libstdc++.so.6 /usr/$LIB/libgcc_s.so.1 /usr/$LIB/libxcb.so.1:/usr/$LIB/libstdc++.so.6 /usr/$LIB/libgcc_s.so.1 /usr/$LIB/libxcb.so.1'
instead of the expected prepending of the path to self, so I guess I somehow messed up the strtok.
I get a lot of errors like those:
Error in 'sh': munmap_chunk(): invalid pointer: 0x00007fff3888af4a
which to me sounds like I'm freeing too much probably, but I can't find the culprit.
I hope this doesn't sound too much like a "hey fix this for me" post but I'm kinda hitting a wall here and any help would be very appreciated.
You cannot assume that an individual string in envp was allocated with malloc so free(string) could be Undefined Behaviour. It is virtually impossible to call exec* with a completely empty heap and the entire image will be replaced anyway, so it's not worth worrying about.
Your second strtok call should supply NULL as its first argument. See man strtok for an explanation and examples.
Do this straight forward:
Create a new pointer array with the size necessary to hold the new env/ var/s
strdup() all elements you need from the old to the new array.
Add new stuff as necessary.
Make sure the last pointer in the array is NULL.
Pass the new pointer array to the original execve().
Do not modify or even (try to) free() entries of the old environment.

Passing string by value in C

After going through multiple examples of passing a string by value in C, I still don't understand why the following code does not work
int main(void){
char *fileList;
strcpy(fileList,"This is a test line\n");
char type = 'F';
if(checkFileList(fileList, type)){
printf("Proper File list\n");
}
else{
printf("Improper File list\n");
}
}
int checkFileList(char *string, char type){
// Do something with string
}
This program works if I define the variable fileList in the main function as-
char fileList[128];
But I can't provide a fixed size to this string as I get the string only at runtime and hence don't know how long it'll be.
What am I doing wrong here? Please note that I don't want to pass the string by reference as I'll be changing the string in the function and don't want this to be reflected in the original string.
In your code
char *fileList;
strcpy(fileList,"This is a test line\n");
invokes undefined behaviour
, as , fileList is used uninitialized.
You need to allocate memory to fileList before using it. Maybe malloc() and family of functions will help you into that. Also, read about free().
FWIW,
This program works if I define the variable fileList in the main function as-
char fileList[128];
because, the fileList is an array here and the memory allocation is already done by the compiler. So, it is ok to use that.
BTW "Passing string by value" is misuse of the terms. C uses pass-by-value for any function parameter passing.
In order to allocate the memory for the string at runtime you better get to know the size of the string first:
int main(void){
const char *str = "This is a test line\n";
int len = strlen(str);
char *fileList = malloc(len);
// then later you also have to take care for releasing the allocated memory:
free(fileList);
}

Am I passing a copy of my char array, or a pointer?

I've been studying C, and I decided to practice using my knowledge by creating some functions to manipulate strings. I wrote a string reverser function, and a main function that asks for user input, sends it through stringreverse(), and prints the results.
Basically I just want to understand how my function works. When I call it with 'tempstr' as the first param, is that to be understood as the address of the first element in the array? Basically like saying &tempstr[0], right?
I guess answering this question would tell me: Would there be any difference if I assigned a char* pointer to my tempstr array and then sent that to stringreverse() as the first param, versus how I'm doing it now? I want to know whether I'm sending a duplicate of the array tempstr, or a memory address.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char* stringreverse(char* tempstr, char* returnptr);
printf("\nEnter a string:\n\t");
char tempstr[1024];
gets(tempstr);
char *revstr = stringreverse(tempstr, revstr); //Assigns revstr the address of the first character of the reversed string.
printf("\nReversed string:\n"
"\t%s\n", revstr);
main();
return 0;
}
char* stringreverse(char* tempstr, char* returnptr)
{
char revstr[1024] = {0};
int i, j = 0;
for (i = strlen(tempstr) - 1; i >= 0; i--, j++)
{
revstr[j] = tempstr[i]; //string reverse algorithm
}
returnptr = &revstr[0];
return returnptr;
}
Thanks for your time. Any other critiques would be helpful . . only a few weeks into programming :P
EDIT: Thanks to all the answers, I figured it out. Here's my solution for anyone wondering:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void stringreverse(char* s);
int main(void)
{
printf("\nEnter a string:\n\t");
char userinput[1024] = {0}; //Need to learn how to use malloc() xD
gets(userinput);
stringreverse(userinput);
printf("\nReversed string:\n"
"\t%s\n", userinput);
main();
return 0;
}
void stringreverse(char* s)
{
int i, j = 0;
char scopy[1024]; //Update to dynamic buffer
strcpy(scopy, s);
for (i = strlen(s) - 1; i >= 0; i--, j++)
{
*(s + j) = scopy[i];
}
}
First, a detail:
int main()
{
char* stringreverse(char* tempstr, char* returnptr);
That prototype should go outside main(), like this:
char* stringreverse(char* tempstr, char* returnptr);
int main()
{
As to your main question: the variable tempstr is a char*, i.e. the address of a character. If you use C's index notation, like tempstr[i], that's essentially the same as *(tempstr + i). The same is true of revstr, except that in that case you're returning the address of a block of memory that's about to be clobbered when the array it points to goes out of scope. You've got the right idea in passing in the address of some memory into which to write the reversed string, but you're not actually copying the data into the memory pointed to by that block. Also, the line:
returnptr = &revstr[0];
Doesn't do what you think. You can't assign a new pointer to returnptr; if you really want to modify returnptr, you'll need to pass in its address, so the parameter would be specified char** returnptr. But don't do that: instead, create a block in your main() that will receive the reversed string, and pass its address in the returnptr parameter. Then, use that block rather than the temporary one you're using now in stringreverse().
Basically I just want to understand how my function works.
One problem you have is that you are using revstr without initializing it or allocating memory for it. This is undefined behavior since you are writing into memory doesn't belong to you. It may appear to work, but in fact what you have is a bug and can produce unexpected results at any time.
When I call it with 'tempstr' as the first param, is that to be understood as the address of the first element in the array? Basically like saying &tempstr[0], right?
Yes. When arrays are passed as arguments to a function, they are treated as regular pointers, pointing to the first element in the array. There is no difference if you assigned &temp[0] to a char* before passing it to stringreverser, because that's what the compiler is doing for you anyway.
The only time you will see a difference between arrays and pointers being passed to functions is in C++ when you start learning about templates and template specialization. But this question is C, so I just thought I'd throw that out there.
When I call it with 'tempstr' as the first param, is that to be understood as the
address of the first element in the array? Basically like saying &tempstr[0],
right?
char tempstr[1024];
tempstr is an array of characters. When passed tempstr to a function, it decays to a pointer pointing to first element of tempstr. So, its basically same as sending &tempstr[0].
Would there be any difference if I assigned a char* pointer to my tempstr array and then sent that to stringreverse() as the first param, versus how I'm doing it now?
No difference. You might do -
char* pointer = tempstr ; // And can pass pointer
char *revstr = stringreverse(tempstr, revstr);
First right side expression's is evaluavated and the return value is assigned to revstr. But what is revstr that is being passed. Program should allocate memory for it.
char revstr[1024] ;
char *retValue = stringreverse(tempstr, revstr) ;
// ^^^^^^ changed to be different.
Now, when passing tempstr and revstr, they decayed to pointers pointing to their respective first indexes. In that case why this would go wrong -
revstr = stringreverse(tempstr, revstr) ;
Just because arrays are not pointers. char* is different from char[]. Hope it helps !
In response to your question about whether the thing passed to the function is an array or a pointer, the relevant part of the C99 standard (6.3.2.1/3) states:
Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue.
So yes, other than the introduction of another explicit variable, the following two lines are equivalent:
char x[] = "abc"; fn (x);
char x[] = "abc"; char *px = &(x[0]); fn (px);
As to a critique, I'd like to raise the following.
While legal, I find it incongruous to have function prototypes (such as stringreverse) anywhere other than at file level. In fact, I tend to order my functions so that they're not usually necessary, making one less place where you have to change it, should the arguments or return type need to be changed. That would entail, in this case, placing stringreverse before main.
Don't ever use gets in a real program.. It's unprotectable against buffer overflows. At a minimum, use fgets which can be protected, or use a decent input function such as the one found here.
You cannot create a local variable within stringreverse and pass back the address of it. That's undefined behaviour. Once that function returns, that variable is gone and you're most likely pointing to whatever happens to replace it on the stack the next time you call a function.
There's no need to pass in the revstr variable either. If it were a pointer with backing memory (i.e., had space allocated for it), that would be fine but then there would be no need to return it. In that case you would allocate both in the caller:
char tempstr[1024];
char revstr[1024];
stringreverse (tempstr, revstr); // Note no return value needed
// since you're manipulating revstr directly.
You should also try to avoid magic numbers like 1024. Better to have lines like:
#define BUFFSZ 1024
char tempstr[BUFFSZ];
so that you only need to change it in one place if you ever need a new value (that becomes particularly important if you have lots of 1024 numbers with different meanings - global search and replace will be your enemy in that case rather than your friend).
In order to make you function more adaptable, you may want to consider allowing it to handle any length. You can do that by passing both buffers in, or by using malloc to dynamically allocate a buffer for you, something like:
char *reversestring (char *src) {
char *dst = malloc (strlen (src) + 1);
if (dst != NULL) {
// copy characters in reverse order.
}
return dst;
}
This puts the responsibility for freeing that memory on the caller but that's a well-worn way of doing things.
You should probably use one of the two canonical forms for main:
int main (int argc, char *argv[]);
int main (void);
It's also a particularly bad idea to call main from anywhere. While that may look like a nifty way to get an infinite loop, it almost certainly will end up chewing up your stack space :-)
All in all, this is probably the function I'd initially write. It allows the user to populate their own buffer if they want, or to specify they don't have one, in which case one will be created for them:
char *revstr (char *src, char *dst) {
// Cache size in case compiler not smart enough to do so.
// Then create destination buffer if none provided.
size_t sz = strlen (src);
if (dst == NULL) dst = malloc (sz + 1);
// Assuming buffer available, copy string.
if (dst != NULL) {
// Run dst end to start, null terminator first.
dst += sz; *dst = '\0';
// Copy character by character until null terminator in src.
// We end up with dst set to original correct value.
while (*src != '\0')
*--dst = *src++;
}
// Return reversed string (possibly NULL if malloc failed).
return dst;
}
In your stringreverse() function, you are returning the address of a local variable (revstr). This is undefined behaviour and is very bad. Your program may appear to work right now, but it will suddenly fail sometime in the future for reasons that are not obvious.
You have two general choices:
Have stringreverse() allocate memory for the returned string, and leave it up to the caller to free it.
Have the caller preallocate space for the returned string, and tell stringreverse() where it is and how big it is.

Problem with pointer copy in C

I radically re-edited the question to explain better my application, as the xample I made up wasn't correct in many ways as you pointed out:
I have one pointer to char and I want to copy it to another pointer and then add a NULL character at the end (in my real application, the first string is a const, so I cannot jsut modify it, that's why I need to copy it).
I have this function, "MLSLSerialWriteBurst" which I have to fill with some code adapt to my microcontroller.
tMLError MLSLSerialWriteBurst( unsigned char slaveAddr,
unsigned char registerAddr,
unsigned short length,
const unsigned char *data )
{
unsigned char *tmp_data;
tmp_data = data;
*(tmp_data+length) = NULL;
// this function takes a tmp_data which is a char* terminated with a NULL character ('\0')
if(EEPageWrite2(slaveAddr,registerAddr,tmp_data)==0)
return ML_SUCCESS;
else
return ML_ERROR;
}
I see there's a problem here: tha fact that I do not initialize tmp_data, but I cannot know it's length.
For starters, you are missing a bunch of declarations in your code. For example, what is lungh? Also, I'm assuming you initialized your two pointers so they point to memory you can use. However, maybe that's not a safe assumption.
Beyond that, you failed to terminate your from string. So getting the length of the string will not work.
There seems to be numerous errors here. It's hard to know where to start. Is this really what your actual code looks like? I don't think it would even compile.
Finally, there seems to be a bit of confusion in your terminology. Copying a pointer is different from copying the memory being pointed to. A pointer is a memory address. If you simply copy the pointer, then both pointers will refer to the same address.
I would create a copy of a string using code similar to this:
char *from_string = "ciao";
char *to_string;
int len;
len = strlen(from_string);
to_string = (char *)malloc(len + 1);
if (to_string != NULL)
strcpy(to_string, from_string);
Be fully aware that you do not want to copy a pointer. You want to copy the memory that is pointed to by the pointer. It does sound like you should learn more about pointers and the memory environment of your system before proceeding too much farther.
When you say tmp_data = data, you are pointing tmp_data to the same memory pointed to by data. Instead, you need to allocate a new block of memory and copy the memory from data into it.
The standard way to do this is with malloc. If you do not have malloc, your libraries may have some other way of acquiring a pointer to usable memory.
unsigned char * tmp_data = malloc(length + 1);
if(tmp_data != 0) {
memcpy(tmp_data, data, length);
tmp_data[length] = 0;
// ...
free(tmp_data);
}
You could also use a fixed-size array on the stack:
unsigned char tmp_data[256];
if(length >= sizeof(tmp_data)) length = sizeof(tmp_data) - 1;
memcpy(tmp_data, data, length); // or equivalent routine
tmp_data[length] = 0;
C99 introduced variable-length arrays, which may be what you seek here, if your compiler supports them:
unsigned char tmp_data[length];
memcpy(tmp_data, data, length); // or equivalent routine
tmp_data[length] = 0;

Resources