How to handle data types? - c

I'm really facing a problem with data types conversions.
I'm making a GUI version of a program with GTK. To get entry_text string I need a const char* which obliges me to use this data type in the function below.
I want to convert it to string(char[]) and compiler keep giving me errors below :
Source code where errors come:
//....
char ret (const char *bd){
char c[100];
strcpy(c,bd);
return *c;
}
char encode(const char ebuf[],const char epass[]) {
char *buf=ret(ebuf);
char *pass=ret(epass);
//...
When I compile the code I get following errors (with g++):
codgui.cpp: In function ‘char encode(const char*, const char*)’:
codgui.cpp:36: error: invalid conversion from ‘char’ to ‘char*’
codgui.cpp:37: error: invalid conversion from ‘char’ to ‘char*’
Anyone have any clue on how to fix this?

Your ret function is only returning the first character in the local variable c. You want to return a char*, and you should never return the address of a local variable, so you will need to create it on the heap.
char* ret (const char *bd){
char *c = new char[100];
strcpy(c,bd);
return c;
}
char encode(const char ebuf[],const char epass[]) {
char *buf=ret(ebuf);
char *pass=ret(epass);

Related

Pointer Functions in C: initialization of foo from incompatible pointer type

I'm working with C, and not allowed to use C++. Currently, I'm trying to implement some level of OOP in C. I'm currently working on trying to implement polymorphism and inheritance.
I've spent the majority of the day reading up on how my goals are possible through the use of function pointers. I am attempting to print the members variables of both structs as seen here:
RecordObject.h
typedef struct SuperRecordObject
{
char *Id;
char *date;
char *cases;
char *deaths;
void (*ptrPrintRecord)(char *id, char *date, char *cases, char *deaths, char *names_fr, char *names_en);
} SuperRecord;
typedef struct ChildRecordObject
{
SuperRecord super;
char *names_fr;
char *names_en;
} ChildRecord;
I have defined the function ptrPrintRecord in this file:
RecordObject.c
#include <stdio.h>
#include "RecordObject.h"
void ptrPrintRecord(char *id, char *date, char *cases, char *deaths, char *names_fr, char *names_en)
{
//char *record;
printf(" %s | %s | %s | %s | %s | %s\n", id, date, cases, deaths, names_fr, names_en);
//return record;
}
And I try to use the function in this file, as such:
DataLayer.c
#include <stdio.h>
#include <string.h>
#include "RecordObject.h"
/* more code here */
void(*fun_ptr)(char*,char*,char*,char*,char*,char*) = &record.super.ptrPrintRecord; //
(*fun_ptr)(record.super.Id, record.super.date, record.super.cases, record.super.deaths, record.names_fr, record.names_en);
/* more code here */
However, when I compile (using GCC), I get this warning which causes a crash.
warning: initialization of 'void (*)(char *, char *, char *, char *, char *, char *)' from incompatible pointer type 'void (**)(char *, char *, char *, char *, char *, char *)' [-Wincompatible-pointer-types]
62 | void(*fun_ptr)(char*,char*,char*,char*,char*,char*) = &record.super.ptrPrintRecord;
I've ran some other pointer functions in other files to mess around and test it, and the only thing I can think of as to what's going on here is it's maybe got something to do with how strings work in C?
You have an extraneous & in your attempted function pointer assignment. The ptrPrintRecord member of your structure is already a function pointer of the correct type, so you don't need the & - which would give the address of that pointer.
Just use:
void(*fun_ptr)(char*, char*, char*, char*, char*, char*) = record.super.ptrPrintRecord; // No &
As a side note, your use of ptrPrintRecord as that member (function pointer) and also as the name of an actual function (with the same 'signature') is likely to cause some issues, further down the road.
Furthermore, you need to actually initialize that member (pointer) to a valid function address before copying it to something you then call (as also with the other members of the structure). Here's a small main (using your other code) that works:
int main()
{
ChildRecord record;
record.super.ptrPrintRecord = ptrPrintRecord; // See my note about the name clash!
record.super.Id = "ID";
record.super.date = "today";
record.super.cases = "cases";
record.super.deaths = "deaths";
void(*fun_ptr)(char*, char*, char*, char*, char*, char*) = record.super.ptrPrintRecord; //
// To call the pointed-to function, we can just use the pointer name:
fun_ptr(record.super.Id, record.super.date, record.super.cases, record.super.deaths, record.names_fr, record.names_en);
return 0;
}

Why I have error: deprecated conversion from string constant to 'char*' [-Wwrite-strings] in the line 5 and 6?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
char *preorden="GEAIBMCLDFKJH";//line 5
error in the above line
char *inorden="IABEGLDCFMKHJ";//line 6
error in this line
char *postorden;
error in this line
void post(char *pre, char *in, char *pos,int n)
{
int longIzqda;
if(n!=0){
pos[n-1]=pre[0];
longIzqda=strchr(in,pre[0])-in;
post (pre+1,in,pos,longIzqda);
post (pre+1+longIzqda,in+1+longIzqda,pos+longIzqda,n-1-longIzqda);
}
}
int main(int argc,char *argv[])
{
int aux;
aux=strlen(preorden);//convert to string
postorden=(char *)malloc(aux*sizeof(char));//use of malloc function
if (postorden){
printf("The preorden is: %s\n",preorden);
printf("The inorden is: %s\n",inorden);
post(preorden,inorden,postorden,aux);
postorden[aux]='\0';
printf("The postorden calculated is: %s\n",postorden);
free(postorden);
}
else{
fprintf(stderr,"Whithout memory\n");
return 1; // return 1
}
return 0;
}
the error is in the line 5 and 6
the compiler says:
deprecated conversion from string constant to 'char*' [-Wwrite-strings]
There are few issues with your code, firstly this
char *preorden="GEAIBMCLDFKJH";//line 5
forces compiler to warn you like below if compiled with -Wwrite-strings flags in C
deprecated conversion from string constant to 'char*'
[-Wwrite-strings]
because the string literal GEAIBMCLDFKJH stored in read only section of primary memory i.e pointer where it points, that contents is read only, hence instead of char* use const char*. for e.g
char *preorden = "GEAIBMCLDFKJH";/* preorden is normal pointer but "GEAIBMCLDFKJH" is read only, hence error */
And
const char *preorden = "GEAIBMCLDFKJH"; /* const char *ptr means ptr contents is read only */
Secondly, here
postorden=(char *)malloc(aux*sizeof(char));//use of malloc function
casting of malloc result is not required as malloc() return type is void* which is automatically and safely promoted to any other pointer type, Read Do I cast the result of malloc?. for e.g
postorden = malloc(aux * sizeof(*postorden));//use of malloc function
Also here(this point is about wrong comment on below line, please don't mind)
aux=strlen(preorden);//convert to string
strlen(preorden) returns the length of string pointed by preorden and gets assigned to aux not as written in comments(convert to string).
And change the post() definition to
void post(const char *pre, const char *in, char *pos,int n) {
/* some code*/
}
The message “deprecated conversion from string constant to 'char*' [-Wwrite-strings]” arises because the code was compiled as C++ code, which has different rules about string literals and pointer conversions from C.
This can be fixed by compiling the code as C code or worked around by inserting an explicit cast to char *.

How to pass commandline argument as part of a string parameter

This is part of the code I'm facing issue with :
void encrypt(const char *fileIn, const char *fileOut, const unsigned char *key);
int main(int argc, char *argv[])
{
const unsigned char key[100];
srand(time(NULL));
aes_init();
encrypt(argv[1], "/home/python/encrypt/"argv[1]".encrypted", argv[3]);
return 0;
}
As you can see, in the encrypt function, I'm asking the user to enter the file name via command line for input. For output of the same function, I wanted the same name to be just appended by '.encrypted'. However, I get the following error whenever I try to compile the code.
In function ‘main’:
error: expected ‘)’ before ‘argv’
error: too few arguments to function ‘encrypt’
note: declared here
What am I doing wrong? Please help.
I think you want something easy string manipulation like this
snprintf(key,100,"/home/python/encrypt/%s.encrypted",argv[1]);
encrypt(argv[1],key, argv[3]);
in C, string manipulation is not as smooth as in modern languages. You have to append strings by using library functions.
char buffer[CCHMAXPATH];
sprintf(buffer, "/home/%s.encrypted", argv[1]);
encrypt(argv[1], buffer, argv[3]);

C: Illegal conversion between pointer types: pointer to const unsigned char -> pointer to unsigned char

The following code is producing a warning:
const char * mystr = "\r\nHello";
void send_str(char * str);
void main(void){
send_str(mystr);
}
void send_str(char * str){
// send it
}
The error is:
Warning [359] C:\main.c; 5.15 illegal conversion between pointer types
pointer to const unsigned char -> pointer to unsigned char
How can I change the code to compile without warnings? The send_str() function also needs to be able to accept non-const strings.
(I am compiling for the PIC16F77 with the Hi-Tech-C compiler)
Thanks
You need to add a cast, since you're passing constant data to a function that says "I might change this":
send_str((char *) mystr); /* cast away the const */
Of course, if the function does decide to change the data that is in reality supposed to be constant (such as a string literal), you will get undefined behavior.
Perhaps I mis-understood you, though. If send_str() never needs to change its input, but might get called with data that is non-constant in the caller's context, then you should just make the argument const since that just say "I won't change this":
void send_str(const char *str);
This can safely be called with both constant and non-constant data:
char modifiable[32] = "hello";
const char *constant = "world";
send_str(modifiable); /* no warning */
send_str(constant); /* no warning */
change the following lines
void send_str(char * str){
// send it
}
TO
void send_str(const char * str){
// send it
}
your compiler is saying that the const char pointer your sending is being converted to char pointer. changing its value in the function send_str may lead to undefined behaviour.(Most of the cases calling and called function wont be written by the same person , someone else may use your code and call it looking at the prototype which is not right.)

C issues with pointers

I'm learning about the pointers in C. I don't understand why this code fails during the compilation process.
#include <stdio.h>
void set_error(int *err);
int main(int argc, const char * argv[])
{
const char *err;
set_error(&err);
return 0;
}
void set_error(int *err) {
*err = "Error message";
}
You declare the function to expect a pointer-to-int (int *). But you give it a pointer-to-pointer-to-char and set_error treats it as such. Change the declaration thusly:
void set_error(const char ** err)
If you had compiled with warnings enabled (-Wall for GCC) it would give the following warnings:
In function 'main':
warning: passing argument 1 of 'set_error' from incompatible pointer type [enabled by default]
set_error(&err);
^
note: expected 'int *' but argument is of type 'const char **'
void set_error(int *err);
^
In function 'set_error':
warning: assignment makes integer from pointer without a cast [enabled by default]
*err = "Error message";
^
Your function expects int * type argument but you are passing to it const char ** type argument.
Change your function declaration to
void set_error(const char **err);
The issue you have unearths an important facts about strings in C.
It also raises an interesting fact about scoping.
1. There is no such thing as a string in C; only a pointer to an array of characters.
Therefore, your statement *err = "Error message"; is wrong because by derefencing err you're not getting to the value of the string, but it's first character. (You can't quantify the 'value of a string' in C because there's no such thing as a string in C)
*err is actually undefined because nothing is yet assigned.
Note that the usual definition of a string is const char * or char * so I've changed this from what you had for the note below:
#include <stdio.h>
int main(void){
char * a = "hello";
if (*a == 'h'){
printf("it's an 'H'\n");
}
else{
printf("no it isn't\n");
}
}
You'll see that *err actually returns the value of the first character because a[0] == *a
2. You cannot return pointers to locally scoped data in C
set_error() has the correct intentions, but is doomed to fail. Although "Error message"looks like a value, it is actually already a pointer (because strings in C are pointers to character arrays, as mentioned above).
Therefore, taking (1) into account you might expect to be able to do this:
void set_int(int *myint) {
*myint = 1; //works just fine because 1 is a value, not a reference
}
void set_error(char *err) {
// doesn't work because you're trying to assign a pointer to a char
*err = "Error message";
void set_error_new(char *err) {
//doesn't work because when the function returns, "Error Message" is no longer available on the stack" (assignment works, but when you later try to get at that data, you'll segfault
err = "Error message";
}
You need to take a different approach to how you play with so-called 'strings' in C. Think of them as a pointer to a character array and you'll get better at understanding these issues. Also see C: differences between char pointer and array
One problem is that set_error expects an int * parameter, but you're passing the address of a char *, which makes it a char **. In addition, as noted by #Kninnug there's a buffer overwrite problem here which needs to be dealt with. Try rewriting your code as:
#include <stdio.h>
#include <string.h>
void set_error(char *err, size_t errbuf_size);
int main(int argc, const char * argv[])
{
char err_buf[1000];
set_error(err_buf, sizeof(err_buf));
printf("err_buf = '%s'\n", err_buf);
return 0;
}
void set_error(char *err, size_t errbuf_size) {
strncpy(err, "Error message", errbuf_size-1);
}
As you'll notice in the rewritten version of set_error, another problem is that you can't just assign a value to a pointer and have the target buffer changed - you need to use the string functions from the standard library (here I'm use strncpy to copy the constant "Error message" to the buffer pointed to by the char * variable err). You may want to get familiar with these.
Share and enjoy.
Firstly you have to change your function's declaration to
void set_error(char **err);
The body of the function is the same. Also you declared err variable as const char *err and tried change it. It generates a warning.
Let's start by talking about types. In your main function, you declare err as
const char *err;
and when you call the set_error function, you pass the expression &err, which will have type "pointer to const char *", or const char **.
However, in your function declaration and definition, you declare the parameter err as
int *err;
The types const char ** and int * aren't compatible, which is why the compiler is yakking. C doesn't allow you to assign pointer values of one type to pointer variables of a different type (unless one is a void *, which is a "generic" pointer type). Different pointer types are not guaranteed to have the same size or representation on a particular platform.
So that's where the compiler issue is coming from; what's the solution?
In C, string literals like "Error message" have type char *1 (const char * in C++), so whatever I assign it to needs to have a type of either char * or const char *. Since we're dealing with a string literal, the latter is preferable (attempting to modify the contents of a string literal invokes undefined behavior; some platforms put string literals in read-only memory, some don't). So you need to make the following changes to your code2:
void set_error( const char **err )
{
*err = "Error message";
}
int main( void ) // you're not dealing with command line arguments, so for this
{ // exercise you can use `void` for your parameter list
const char *err;
set_error( &err );
return 0;
}
Remember that C passes all function arguments by value; this means that the formal parameter err in set_error is a different object in memory than the actual parameter err in main; if the code had been
void set_error( const char *err )
{
err = "Error message";
}
int main( void )
{
const char *err;
set_error( err );
return 0;
}
then the change to err in set_error would not be reflected in the variable err in main. If we want set_error to modify the value of err in main, we need to pass set_error a pointer to err and dereference it in the function. Since the parameter err has type const char **, the expression *err has type const char *, which is the type we need for this assignment to succeed.
1. Actually, that's not true; string literals have type "N-element array of char", where N is the number of characters in the string plus the 0 terminator. However, for reasons that aren't really worth going into here, the compiler will convert expressions of array type to expressions of pointer type in most circumstances. In this case, the string literal "Error message" is converted from an expression of type "14-element array of char" to "pointer to char".
2. A function definition also serves as a declaration; I typically put the called function before the caller so I don't have to mess with separate declarations. It means my code reads "backwards" or from the bottom up, but it saves some maintenance headaches.
1st error--> You are noticing is due to the fact that your function expects a pointer to int and you are passing a pointer to const char
2nd error--> You dereferenced the pointer and inserted the value "Error Message" which is a string and you pointer was pointer to char.
3rd error--> set_error(&err); --> This statement is wrong as err itself stores an address so there is no need to put & putting & means you are passing the address of the pointer *err and not the address which it is holding. So try this.
include <stdio.h>
void set_error(const char* err[]); //Function Declaration
int main()
{
const char* err[1000];
set_error(err);
printf("%s",*err);
return 0;
}
void set_error(const char* err[])
{
*err = "Error Message";
}

Resources