warning about incompatible pointer type - c - c

I call my function from my main as so...
int main() {
char* input[81];
char** array[81];
userInput(input);
parseInput(input);
}
userInput is taking in input and storing in the input variable. this is working correctly.
but now I want to send both the input and a char pointer array to my parseInput function to parse the input into an array using strtok
the following is my parseInput() function...
void parseInput(char* in) {
char *tok = strtok(in, " ");
int i = 0;
while(tok != NULL) {
array[i] = tok;
tok = strtok(NULL, " ");
i++;
}
}
when I try to compile I am getting the following warning and I do not understand why.
warning: passing argument 1 of ‘userInput’ from incompatible pointer type [enabled by default]
userInput(input);
warning: passing argument 1 of ‘parseInput’ from incompatible pointer type [enabled by default]
parseInput(input, array);
Any guidance would be greatly appreciated. thank you

You defined the function parseInput as taking a parameter of type char*, but in the function main, you are passing it a decayed parameter of type char**. That is why your compiler is complaining about an incompatible pointer type.
Instead of
char* input[81];
you should probably write:
char input[81];
Also, the declaration
char** array[81];
should probably be changed to:
char* array[81];
Also, as already pointed out in the comments section, the function parseInput will not compile, because it refers to an identifier array, but no identifier with that name is visible to that function. It cannot see the identifier array of the function main. Therefore, if you want the function parseInput to have access to array in the function main, then, when calling parseInput, you must pass a pointer to that array.
An additional problem with your code is that the behavior of the function parseInput does not make sense, as the caller of that function (in this case main) has no way of knowing how many elements of the pointer array were written by parseInput. Therefore, it has no way of knowing how many elements of the array are valid after the function call. For this reason, it would probably make more sense to make the function parseInput return an int which specifies the number of array elements written.
Another problem is that the function parseInput simply assumes that the passed array is large enough. If that assumption is false, then it will cause a buffer overflow. Therefore, it would probably be safer to design the function parseInput in such a way that it is also passed an argument which specifies the size of the passed array, so that the function can stop before a buffer overflow occurs.
After applying all of the modifications mentioned above, the function parseInput would look like this:
int parseInput( char* in, char** results, int results_length )
{
char *tok = strtok(in, " ");
int i = 0;
while( tok != NULL && i < results_length )
{
results[i] = tok;
tok = strtok(NULL, " ");
i++;
}
return i;
}
Instead of calling the function like this
parseInput(input);
you would now call it like this:
int main(void)
{
char input[81] = "This is a test.";
char* array[81];
int num_elements;
num_elements = parseInput( input, array, sizeof array / sizeof *array );
for ( int i = 0; i < num_elements; i++ )
{
printf( "%s\n", array[i] );
}
return 0;
}
This test program provides the following output:
This
is
a
test.

Related

Array of string in C: OK within a function, full of garbage in main()

An array of strings is created in main and passed to a function. This function reads strings from a file and stores every line of the file in a different row of the array. Then finishes and returns to main. If I printf the contents of array[i] within the function, the text displayed in the screen is OK. If I do the same after returning to main(), printf writes only garbage. Why is main() not accessing the contents of the memory positions of the array?
void createlist(char* file, char **mylist) {
FILE* stream;
char name[40];
int i = 0;
stream = fopen(file, "r");
while (fgets(name, sizeof(name), stream) != NULL) {
mylist[i] = name;
printf(mylist[i]); // <------------------------This works OK!
i++;
}
fclose(stream);
}
void main(int argc, char* argv[]) {
char list[3000][40];
int i = 0;
resetchararray(list, 3000);
createlist("file", list);
for (i = 0; i < 3000; i++) {
printf(list[i]); // <---------------------This writes garbage
}
}
name is a local variable in your function. It disappears after the function ends and leaves only garbage behind. To achieve what you are trying, use strcpy(), instead of mylist[i] = name;.
What is happening currently:
createlist("file", list); pass list by value #Shark warns!
mylist[i] = name; makes mylist[i] hold the address of a local variable!
createlist() terminates, having changed only a local copy of list (see point 1)
Compiling your code gives the warning:
program.c:26:24: warning: passing argument 2 of ‘createlist’ from incompatible pointer type [-Wincompatible-pointer-types]
createlist("file", list);
^
program.c:3:6: note: expected ‘char **’ but argument is of type ‘char (*)[40]’
void createlist(char* file, char **mylist) {
which tells you what one of the problems you have is -- the pointer you are passing to createlist is the wrong type. As declared, createlist expects an array of pointers, but you're trying to pass in an array of arrays. There are other problems, such as storing the address of a local variable in your pointer array -- which will be invalid after the function returns.

Add numbers to filename

I want to store data in different files. Therefore I want to create files as follows: data_1.log, data_2.log, ..., data_N.log. The appendix .log is not necessary but would be nice. All my approaches failed so far. Here is one sample that is probably close to what I need:
#include <stdio.h>
#include <string.h>
char get_file_name(int k){
int i, j;
char s1[100] = "logs/data_";
char s2[100];
snprintf(s2, 100, "%d", k);
for(i = 0; s1[i] != '\0'; ++i);
for(j = 0; s2[j] != '\0'; ++j, ++i){
s1[i] = s2[j];
}
s1[i] = '\0';
return s1;
}
int main(){
char file_name[100];
for(int k=0; k<10; k++){
// Get data
// ...
// Create filename
strcpy(file_name, get_file_name(k));
printf("%s", file_name);
// fp = fopen(file_name, "w+");
// Write data to file
// print_results_to_file();
// fclose(fp);
}
return 0;
}
At the moment I get the following errors which I don't understand:
string.c: In function ‘get_file_name’:
string.c:14:12: warning: returning ‘char *’ from a function with return type ‘char’ makes integer from pointer without a cast [-Wint-conversion]
return s1;
^~
string.c:14:12: warning: function returns address of local variable [-Wreturn-local-addr]
string.c: In function ‘main’:
string.c:24:27: warning: passing argument 2 of ‘strcpy’ makes pointer from integer without a cast [-Wint-conversion]
strcpy(file_name, get_file_name(k));
^~~~~~~~~~~~~~~~
In file included from string.c:2:
/usr/include/string.h:121:14: note: expected ‘const char * restrict’ but argument is of type ‘char’
extern char *strcpy (char *__restrict __dest, const char *__restrict __src)
^~~~~~
Is there a more simpler way to create such filenames? I can't believe that there isn't one.
There are various issues with this code and rather than correcting them one by one here’s an alternative approach. It’s not the only one but it’s simple and should be easy to understand and adapt:
#include <stdio.h>
void get_file_name(int k, char* buffer, size_t buflen) {
snprintf(buffer, buflen, "logs/data_%d.log", k);
}
int main() {
const size_t BUFLEN = 50;
char file_name[BUFLEN];
for (int i = 0; i < 10; i++) {
get_file_name(i, file_name, BUFLEN);
printf("%s\n", file_name);
// Code for writing to file.
}
}
A few details:
Rather than attempting to return (pointers to) memory, this function passes a buffer that is written to. It’s up to the caller to ensure that the buffer is big enough (this is always the case here, but if the actual filenames are longer, you should add logic that inspects the return value of snprintf and performs appropriate error handling).
The actual logic of the function requires only a single call to snprintf, which already performs everything you require, so it’s unclear whether having a separate function is even necessary or helpful.
The above uses variable-length arrays. If you want to ensure constant buffers, you can use a #define instead of a const size_t variable for the buffer length. However, using a variable-length array here is fine, and some compilers even convert it into a constant array.
As mentioned in comments, it’s important that you (a) read and understand the documentation of the functions you’re using, and (b) read and understand the compiler error messages.
The function get_file_name has return type char
char get_file_name(int k){
but it returns an object of type char *
char s1[100] = "logs/data_";
//...
return s1;
Moreover the returned pointer points to a local array s1 that will not alive after exiting the function.
In this call
strcpy(file_name, get_file_name(k));
the type of the second argument (that is char according to the function get_file_name declaration) shall be char *.
There is neither the function print_results_to_file declaration nor its definition.
According to the C Standard the function main without parameters shall be declared like
int main( void )
I would write the function get_file_name the following way
#include <stdio.h>
#include <string.h>
char * get_file_name( char *file_name, size_t n, size_t padding )
{
const char *common_part = "logs/data_";
snprintf( file_name, n, "%s%zu", common_part, padding );
return file_name;
}
int main( void )
{
enum { N = 100 };
char file_name[N];
for ( size_t i = 0; i < 10; i++ ) puts( get_file_name( file_name, N, i ) );
}
The program output is
logs/data_0
logs/data_1
logs/data_2
logs/data_3
logs/data_4
logs/data_5
logs/data_6
logs/data_7
logs/data_8
logs/data_9
There are several problems with your code, but the biggest one is that you are trying to return a pointer to a local variable from get_file_name.
This is a big no no since the memory allocated for char s1[100] in get_file_name is freed immediately after return.
The rest of the errors are because you forgot the * in char get_file_name(int k).
There are several possible solutions:
Pass in a char array for the function to fill.
Use a global variable (This is considered a bad practice).
Dynamically allocate the memory.
Make the local variable static (this is a bit hacky, but legal)
Your errors are easily explained:
get_file_name should return a char but you create a char[] and return this(it isthe same as char*)
get_file_name returns the adress of an array that is created in the function itself. After the function ends, the array may be overwritten. Add the array as parameter or use malloc
strcpy does not work because it expects a char* (char[]) and not a char. get_file_name returns a char.
print_results_to_file is not defined. You may need to include other files you use in the program (e.g. if the function is implemented in a file func.c the prototype should be in a file called func.h that is included via #include "func.h".

error function return in c

I need recive the char* from a function but I don't understand what is wrong.
int main(int argc,char** argv)
{
char *respuesta;
respuesta = comunicacion(comando);
printf("respuesta uno %s",respuesta);
return EXIT_SUCCESS;
}
char *comunicacion(char data[])
{
unsigned char c ='d';
char *respuesta;
append(respuesta,c);
return respuesta;
}
void append(char* s, char c)
{
int len = strlen(s);
s[len] = c;
s[len+1] = '\0';
}
this is the error:
main.c:24:15: warning: assignment makes pointer from integer without a cast [enabled by default]
The reason you see the "assignment makes pointer from integer without a cast" warning is that your comunicacion function lacks a prototype. When this happens, C assumes that your function returns an int, and all its parameters are int as well. Since neither of these is true about your comunicacion function, your code has undefined behavior.
Another problem is that comando is undefined. Finally, when you call append, respuesta is uninitialized. Using it in any way inside the append function would be undefined behavior, so the call strlen on the vale that's uninitialized is illegal.
Finally, note that the data parameter is unused in the comunicacion function. This needs to be changed - either use the parameter, or remove it from the function's signature.
in respuesta = comunicacion(comando); .... the compiler is assuming that comunicacion returns an int, since it has not seen a prototyp[e or definition. This is likely what generates the warning.
in main(), comando apparently has not been declared. Had it already been defined as a global variable?
in comunicacion(), respuesta is never set to anything. The call to append can have no effect on the value of respuesta.

Counting words from argument in C

I'm new to C and I try to make a program counting words in a sentence given as arguments when running the program. A word is a character or several seperated by either: ' ', '\n', ',' or '.'. Example: ./words abc abc = 2 words
But I keep getting: "segementation fault(core dumped)". Following is code:
int main(char **argv)
{
char buf[80];
sprintf(buf,"%d words\n",words(argv));
write(1,buf,strlen(buf));
return 0;
}
int words(char **argv)
{
int i=0, sum=0;
while(argv[i] != '\0')
{
if(argv[i] == '.' || argv[i] == ',' || argv[i] == ' ' || argv[i] == '\n')
sum++;
i++;
}
}
Argv is a **char or a pointer to an array of strings. Your code is treating it as if it is a single string so is looping through the pointers to strings and counting them. As none of these pointers is null the program continues beyond the end of the array causing a segfault.
me.c:2:5: warning: first argument of âmainâ should be âintâ [-Wmain]
me.c:2:5: warning: âmainâ takes only zero or two arguments [-Wmain]
me.c: In function âmainâ:
me.c:4:1: warning: implicit declaration of function âwordsâ [-Wimplicit-function-declaration]
me.c:5:1: warning: implicit declaration of function âwriteâ [-Wimplicit-function-declaration]
me.c:5:1: warning: implicit declaration of function âstrlenâ [-Wimplicit-function-declaration]
me.c:5:13: warning: incompatible implicit declaration of built-in function âstrlenâ [enabled by default]
me.c: In function âwordsâ:
me.c:11:16: warning: comparison between pointer and integer [enabled by default]
me.c:11:33: warning: comparison between pointer and integer [enabled by default]
me.c:11:51: warning: comparison between pointer and integer [enabled by default]
me.c:11:69: warning: comparison between pointer and integer [enabled by default]
gcc -Wall filename.c will produces all of the above warnings
These are the warnings in your code. Avoid all. and then try.
Please found Answers for these By searching on google
how to use command line arguments
how to declare a function
how to compare strings and how '.' is differ from "."
If I am not mistaken, then the arguments are automatically split into separate character strings. This is why you get a pointer to a pointer (e.g char ** instead of char*). You are dereferencing the argv array only once. Try this:
while(argv[i] != NULL) {
i++;
}
Second, you wont be able to detect newlines that way, since by definition you cannot pass newline in the arguments. What you probably want to do is parse the input from stdin and invoke your program like this:
echo "abc abc" | ./words
or
./words < SOME_TEXT_FILE
Last but not least your words function does not return anything, it needs to return i:
int words(char** argv) {
//...
return i;
}
That is probably the reason why your program segfaults, since the return value of words() will be NULL and then sprintf will try to dereference the result of the function.
So the whole function needs to look somewhat like this:
int words(char** argv) {
int counter = 0;
while(char[i] != NULL) {
int j = 0;
while(char[i][j] != '\0') {
if(char[i][j] == '.') { //no need to check for '\n'...
counter++;
}
j++;
}
i++;
counter++;
}
return counter;
}
1. Iterate over argv.(having in mind that argv[i] is a pointer to char, argv[0] holds name of the program being executed, and last element of argv is NULL pointer.
2. use strtok function from string.h library to split argv[i] with " .,\n". (every time strtok returns non-NULL value you increment words count).
With some reading on command line arguments and strtok you can easily make it work with any arguments passed.

Modifying an array from another function in C

Here is my main function:
main(){
int *seats[50] = {0};
char x;
do{
printf("A-Add Reservation\tC-Cancel Reservation\n");
scanf("%c", &x);
} while(x != 'a' && x != 'c');
switch(x){
case 'a':
addRes(&seats);
break;
default:
break;
}
}
I am trying to pass seats[] into the addRes() function so I can modify it within addRes(). Here is the function:
void addRes(int **seats[]){
int s, i, scount=0, j=0, k=0, yourseats[]={0};
printf("How many seats do you require? ");
scanf("%i\n", &s);
for(i=0;i<=sizeof(*seats);i++){
if(*seats[i] == 0)
scount++;
}
if(scount >= s){
for(i=0;i<=s;){
if(*seats[i] == 0){
yourseats[j]=i;
*seats[i]=1;
i++; j++;
}
else i++;
}
printf("Your seat numbers are: \n");
while(k < j){
printf("%i\n", yourseats[k]);
k++;
}
}
else {
printf("Sorry, there are not enough seats available.\n");
}
}
It compiles with the warnings:
Line 15 (*seats[i]=1;) Assignment makes pointer from integer without a cast.
Line 53: (addRes(&seats);) Passing argument 1 of 'addRes' from incompatible pointer type.
Line 3: (void addRes(int ** seats[]){) Expected 'int ***' but argument is of type 'int *(*)[50]'.
On running the program it gets to
How many seats do you require?
and does nothing after entering a value.
Any help would be much appreciated!
Declaration int **seats[] in function parameter is == int ***seats, and this means type of *seats[i] is int* and you are assigning a number to it, that is incompatible type error:
*seats[i] = 1;
^ ^ int
|
int*
incompatible types
Next in addRes(&seats);
seats in array of pointer its type if int*[50] that &seat is pointer of array and type of &seat is int*(*)[50] Where as function argument type is int ***, so again type incompatible error.
Notice you are also getting a reasonable error message from compiler: Expected 'int ***' but argument is of type 'int * (*)[50]'.
Suggestion:
As I can see in your code, you don't allocate memory for seats[i] in your function addRes() and So as I understand you not need to declare seat[] array as array of pointers but you need simple array of int.
Change declaration in main():
int *seats[50] = {0};
should be just:
int seats[50] = {0};
// removed * before seats
Next just pass seats[] array's name to addRes() function where declaration of function should be
addRes(int* seats)
or addRes(int seats[])
it make your work pretty simple in function addRes() you can access its elements as seats[i] ( and it no need to use extra * operator).
Length of array:
One more conceptional problem in your code that you are using sizeof(*seats) to know the length of array. Its wrong! because in addRes() function seats is not more an array but a pointer so it will give you the size of address ( but not array length).
And yes to inform about size of seats[] in addRes() function send an extra parameter called length, so finally declare addRes() as follows (read comments):
void addRes(int seats[], int length){
// access seat as
// seat[i] = 10;
// where i < length
}
Call this function from main() as follows:
addRes(seats, 50);
// no need to use &
One more problem that presently you are not facing but you will encounter soon as you will run you code that scanf() need extra enter in function addRes(). To resolve it change: scanf("%i\n", &s); as scanf("%i", &s); no need of extra \n in format string in scanf().
int *seats[50] = {0};
This is an array of integer pointers, all you need is an actual array so drop the * resulting in int seats[50] = {0};.
Also your function signature for an array is wrong, void addRes(int seats[]) will do fine.
Finally, to pass an array to that new signature, you can pass the array directly without any unary address-of operators (arrays will decay to a pointer when passed as an argument to a function):
addRes(seats);
Also as pointed out, when assigning to an array element, you need to drop the *:
seats[i]=1;
Is more than enough. Same goes for the if statements and the like where you do a comparison against an array element.
Regarding your addRes function:
for(i=0;i<=sizeof(*seats);i++)
You will only get the size of the pointer this way, which on a 32bit machine is 4. This trick will not work on an array passed to a function. You will need to pass the array separately.
You can fix it in the following way:
Change the function signature of address to this:
void addRes(int seats[], int size)
Pass the size in one of the following ways in main:
Directly: addRes(seats, 50);
Indirectly: addRes(seats, sizeof(seats)/sizeof(int));
Note that the above only works on local to the scope of this function arrays, it won't work on an array you've obtained as an argument to a function (or dynamically allocated arrays).
Another issue is to do with scanf, you should drop the \n. Use scanf("%i", &s);

Resources