Function pointer different behaviour in GCC and Arduino - c

In my C program I have a skeleton for a command interpreter. It works fine on Linux/GCC, but in Arduino it does not return the expected results.
Below find the PC code. I did the appropriate changes for Arduino, and it works except the return string (see second line from bottom in listing).
C-Code on PC (working):
#include <stdio.h>
char* help(char *s){
char *helpString="This is the help string\n";
return helpString;
}
typedef struct {
const char* command;
char* (*cmdExec)(char *s);
}S_COMMAND;
S_COMMAND cmdTable[]= {
{"he", help}
};
int main(void){
char *text;
printf("\n%s\t",cmdTable[0].command); // returns "he"
text = (cmdTable[0].cmdExec)("0");
/* returns help string on PC as expected, but garbage on Arduino */
printf("\n%s", text);
}

Thanks for the advice. I modified the code like follows (peeking at Node.JS), and it is working fine now on both platforms.
int help(char *req, char *res){
strcpy(res, "This is the help string...\n");
return 0;
}
typedef struct {
char* command;
int (*cmdExec)(char *request, char *result);
}S_COMMAND;
S_COMMAND cmdTable[]= {
{"he", help}
};
int main(void){
char text[20];
cmdTable[0].cmdExec("0", text);
}

This is valid C code (with the exception of the missing return statement in main), and a conforming C compiler should accept it and produce a working executable. In particular, your use of function pointers isn’t related to the problem at hand. Furthermore, the manual for avr-gcc does not mention any relevant restrictions. I don’t have an Arduino on hand to test the behaviour but if avr-gcc does not produce working code for the input you’ve shown then this suggests a bug in the compiler.

char* help(char *s){
char *helpString="This is the help string\n";
return helpString;
}
You're returning a local variable - it ceases to exist once you go out of scope from the function. That it works at all on any platform is pure luck as once it ceases to exist, trying to access the string is undefined behaviour.

Related

returning string from a function but prints null, what is the reason?

I am trying to return a string from str function but it prints (null)
#include<stdio.h>
char* str()
{
char hi[10] = "return this";
return hi;
}
void main()
{
printf("%s", str());
}
read static variables or global variables to access the variable outside the functions
there is an overflow in your code, read buffer overflow in c
Also read What should main() return in C and C++?
#include<stdio.h>
char* str()
{
static char hi[] = "return this";
return hi;
}
int main()
{
printf("%s", str());
return 0;
}
In GCC at least your code compiles with teh following warnings:
main.c:12:19: warning: initializer-string for array of chars is too long
main.c:13:12: warning: function returns address of local variable [-Wreturn-local-addr]
Which more or less is a direct answer to your question. If you did not get these warnings, consider the compiler switched you are using, for GCC I suggest at least -Wall -Werror - that will output the most useful warnings without being pedantic, and make those warnings errors so will prevent successful compilation until you fix them.
You are returning a pointer to a local-automatic variable that is no longer in scope after the function returns, so the result is undefined. You have also tried to initialise an array with more characters that you have reserved.
What the compiler has done here is given the invalid initialiser, it has set the address of hi to null, and printf has handles the null pointer by printing (null). That is behaviour specific to your compiler and C library - in other cases something different may happen. More insidious that that is that if your initialiser was not invalid (by being shorter), it is likely to have appeared to work and you might never have asked the question, but it would still be incorrect, and in more complex code would likely at some point cause observable erroneous behaviour.
In this particular case you could do any of the following:
const char* str()
{
static const char* hi = "return this";
return hi;
}
const char* str()
{
static const char hi[] = "return this";
return hi;
}
char* str( char* str, int maxlen )
{
str[maxlen] = '\0' ;
return strncpy( str, "return this", maxlen - 1 ) ;
}
void main()
{
char* buffer[32] ;
printf("%s", str(buffer, sizeof(buffer));
}
The most appropriate solution (and the above are by no means exhaustive) depend on what you actually want to do, since each solution differs semantically, and on its own this function is hardly practical. It would need a concrete real-world example to give best advice.
The problem is with the scope of the character array.
The solution for this issue is to make the address of that variable visible to the caller function!
i.e.
one of the easiest solutions is use the below line in the declaration part of hi variable in your str() function.
i.e.
static char hi[10] = "return th";
in the declaration.
This way you wouldn't need to change anything in this program BUT in the whole program, this variable WILL BE visible/accessible throughout the execution.
#include"stdio.h"
char* str() {
static char hi[10] = "return th";
return hi;
}
int main() {
printf("%s", str());
return 0;
}
#include<stdio.h>
#include<stdlib.h>
char* str(){
//malloc is used to allocate memory
char *hi=(char*)malloc(sizeof(char)*20);
char ch[]="return this\0";
for(int i=0;i<sizeof(ch);i++)
hi[i]=ch[i];
return hi;
}
int main(){
printf("%s", str());
return 0;
}
you can find more about malloc and sizeof operator.

How to pointer reference dynamic sized pointer to array?

I want to be able to reference variable sized array with a global pointer. But what kind of pointer do I use that will work with variable sizes of the array? In the example below, assume N will only be known at runtime (could be an argument for example) so compile time solutions won't work.
What I want to achieve:
main.c
some_sort_of_pointer *x;
main()
{
int N=256; //or N=64 or whatever
char (*LC)[N];
LC=malloc(1024);
x=LC;
memcpy(x[2],"hello world",11);
x[0][176]=123;
dostuff();
}
I'm sure there's an easy obvious way to do this but I can't seem to nail it. My first attempt at asking this was a mess so this time I'm hoping it's clear what I want to achieve.
OS Centos 6.5
compiler GCC 4.8 (using C99)
As at compile time the type to be referenced isn't given, a void pointer might help.
However only storing an untyped reference (what void * in fact is is) is not enough, as it is essential to also know the size of the (VL)array. So the latter also needs to be stored globally, as it can not be pulled from the memory referenced.
An example how this can be achieve is given below:
main.h:
#include <stdlib.h> /* for size_t */
struct VLA_descriptor
{
void * p;
size_t s;
}
extern struct VLA_descriptor vla_descriptor;
foo.h:
void foo(void);
foo.c:
#include "main.h"
#include "foo.h
void foo(void)
{
char (*p)[vla_descriptor.s] = vla_descriptor.p;
/* Do something with the VLA reference p. */
}
main.c:
#include "main.h"
#include "foo.h"
struct VLA_descriptor vla_descriptor = {0};
int main(int argc, char ** argv)
{
size_t s = atoi(argv[1]);
char (*p)[s] = malloc(s);
vla_descriptor.p = p;
vla_descriptor.s = s;
foo();
... /* Free stuff and return. */
}
Error checking had been omitted in this example's code for the sake of readability.
With much thanks to #alk (and everyone else who responded) I think I have the closest I'm going to get to what I'm looking for:
void *LC
int LCS;
int main(int argc, char **argv) {
LCS=256;
LC=malloc(1024)
memcpy(((char(*)[LCS])LC)[2],"hello world",11);
((char(*)[LCS])LC)[0][176]=123;
printf("%d %s\n",((char(*)[LCS])LC)[0][176],&((char(*)[LCS])LC)[2]);
}
((char(*)[LCS])LC) is the equivalent of a what I wanted. It's similar to #alk's idea and does require 2 globals but it means I can use it in functions without having to declare a new variable. I've credited #alk with the answer as what he posted gave me 90% of what I needed.
Though if anyone can reduce ((char(*)[LCS])LC) to a single global, I would be excited to see it :)

Why out-of-bounds occurs with memchr() on mac os

I encounter a problem of overflow when use memchr() on mac os x.
Here is my test code:
#include <stdio.h>
#include <stdlib.h>
int main(void){
char *content="http\r\nUser";
int content_size = strlen(content);
char *contmem = malloc(content_size+1);
memset(contmem, '\0', content_size+1);
memcpy(contmem, content, content_size);
printf("%c\n", *(content+content_size));
printf("%c\n", *(contmem+content_size));
char *t = memchr(content, 't', content_size);
printf("%c\n", *t);
return 0;
}
It works normally on linux, i.e., my fedora 16, and prints the correct value of t.
But when I run the same piece of code on Mac, Segmentation Fault occurs!!
After debugging with gdb, I take the saying:
(gdb) print t
$7 = 0xf4b <Address 0xf4b out of bounds>
Then I try to rewrite the memchr function in this test file:
static char*
memchr(const char *data, int c, unsigned long len){
char *tp = data;
unsigned long i;
for( i = 0; i<len; i++){
if((int)*tp == c){
return tp;
}else{
tp = tp+1;
}
}
}
And the output seems correct!
(gdb) print t
$1 = 0x100000f1d "ttp\r\nUser"
So I am confused with the abnormal behavior of memchr() on mac os, while other mem functions like memset() memcpy() works fine.
How can I run the test without rewriting the memchr() on mac??
Thanks.
The function memchr() is declared in string.h, for which there is no include directive in the posted code. This means an implicit function declaration will be generated by compiler (which should emit a warning) which returns an int. If the sizeof(int) and sizeof(char*) are different on your system this may explain the problem. Add:
#include <string.h>
Your code should indeed work. Your compiler may be using built-in versions of the mem***() functions. Try to include string.h to force the use of the libc versions.

Clarification on why this C code works

I'm learning C today. I've been coding in managed languages (Java, C#, Python, etc.) for some time now. I thought I was understanding the details of pointers, but then I wrote the following code that worked as expected, but generated an 'incompatible pointer type' warning.
void setText(char* output) {
//code to set output to whatever, no problems here.
}
int main(int argc, const char* argv[]) {
char output[10];
setText(&output);
//[EDITED] ...other test code which printf's and further manipulates output.
return 0;
}
So I googled, and ended up changing the line
setText(&output);
to
setText(output);
which got rid of the warning. But now I don't know why the first one was working at all. I was sending the address of an address as far as I can tell (because char* x; is essentially the same as char x[];). What am I misunderstanding and why do both of these work?
The type of output is char [10], which decays to a char * in the context of a function call (which is why the second variant works).
The type of &output is char (*)[10], i.e. a pointer-to-array. This is not the same thing, hence the compiler warning. However, the value of &output (an address) is equivalent to the value of output (once it has decayed to a char *), so the end result is "as expected".
This may sound like pedantry, but there is a fairly important difference. Try the following:
void foo(const char *p)
{
printf("%s\n", p);
}
int main(void)
{
char output[][6] = { "Hello", "world" };
foo(output[0] + 1);
foo(&output[0] + 1);
}
Recommended reading is the C FAQ on arrays and pointers, in particular question 6.3 and 6.12.

Cannot return and assign char array to pointer in C

char *test = "hello";
test = change_test("world");
printf("%s",test);
char* change_test(char *n){
printf("change: %s",n);
return n;
}
im trying to pass a 'string' back to a char pointer using a function but get the following error:
assignment makes pointer from integer without a cast
what am i doing wrong?
A function used without forward declaration will be considered having signature int (...). You should either forward-declare it:
char* change_test(char*);
...
char* test = "hello";
// etc.
or just move the definition change_test before where you call it.
printf() prints the text to the console but does not change n. Use this code instead:
char *change_test(char *n) {
char *result = new char[256];
sprintf(result, "change: %s", n);
return result;
}
// Do not forget to call delete[] on the value returned from change_test
Also add the declaration of change_test() before calling it:
char *change_test(char *n);
You're converting an integer to a pointer somewhere. Your code is incomplete, but at a guess I'd say it's that you're not defining change_test() before you use it, so the C compiler guesses at its type (and assumes it returns an integer.) Declare change_test() before calling it, like so:
char *change_test(char *n);
thanks a bunch guys! didnt think i would have this problem solved by lunch. here is the final test class
/* standard libraries */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* change_test(char*);
int main(){
char *test = "hello";
test = change_test("world");
printf("%s",test);
return (EXIT_SUCCESS);
}
char* change_test(char *n){
return n;
}

Resources