I am trying to pass an array of pointers to strings (names) into a function (foo) and read from it. The below code produces a segmentation fault. Can someone please help me figure out why this code is resulting in a segmentation fault? I want to be able to pass the array names[][] through a function and work with the data like I would if I were using names[][] outside the function.
void foo(char *bar[]) {
printf("%s\n", bar[0]);
}
//---------------Main-------------
char args[][50] = {"quick", "brown", "10", "brown", "jumps", "5"};
int i = 0;
int numbOfPoints = (sizeof(args)/sizeof(args[0]))/3;
//array of all the locations. the number will be its ID (the number spot in the array)
//the contents will be
char names[numbOfPoints][100];
for(i = 0; i < numbOfPoints; i++) {
char *leadNode = args[i*3];
char *endNode = args[i*3 + 1];
char *length = args[i*3 + 2];
int a = stringToInt(length);
//add name
strcpy(names[i],leadNode);
}
//printing all the names out
for(i = 0; i < numbOfPoints; i++) {
printf("%s\n", names[i]);
}
foo(names);
The problem is the the argument type of foo and the way you are calling it. The argument type of foo, char* [] is not compatible with name. I get the following warning in gcc 4.8.2 with -Wall.
soc.c:35:4: warning: passing argument 1 of ‘foo’ from incompatible pointer type [enabled by default]
foo(names);
^
soc.c:5:6: note: expected ‘char **’ but argument is of type ‘char (*)[100]’
void foo(char *bar[]) {
Change foo to:
void foo(char (*bar)[100]) {
printf("%s\n", bar[0]);
}
and all should be well.
Related
I am writing a program to check if a string is inside an array of strings.
I predefined an array of words before the main method
const char *items[] = {"a","b","c","d"};
then I have a function like
bool isInside(const char *array[], char *s1){
//which will try to compare all strings from the input array with s1
int len = sizeof(array)/sizeof(array[0]);
for (int i =0; i< len ; i++){
//do string comparasion}
}
It worked before but not sure where I messed up the code now I got two errors and the function is only able to check the first string of the array with s1.
I found out the problem is that now len = 1 always.
one of the errors is
`warning: ‘sizeof’ on array function parameter ‘array’ will return size of ‘const char **’ [-Wsizeof-array-argument]` and the other one is
isInside(items, words[i]))
| ^~~~~~~~~
| |
| const char **
code.c:63:21: note: expected ‘char *’ but argument is of type ‘const char **’
How can I fix this or call this function so the length is correct and no type warning?
Thanks a lot.
Arrays in C will degrade to pointers when passed as arguments to functions. When they become pointers, their length cannot be retrieved by sizeof.
You should pass the length of arrays as an additional argument to the function.
Maybe your function can be modified as:
bool isInside(const char **array, int arrayLength, char *s1){
for (int i =0; i< arrayLength; i++){
const char* str = array[i];
if(strcmp(str, s1) == 0){
return 1;
}
}
return 0;
}
I'm an absolute beginner at C. I'm trying to develop a shell where I have a 'history' command which prints out the last 5 commands.
Following is my looping function:
void lsh_loop(void)
{
char *line;
char **args;
int status;
do {
printf("> ");
line = lsh_read_line();
args = lsh_split_line(line);
store_history(*line);
status = lsh_execute(args);
free(line);
free(args);
} while (status);
}
And it calls the function to update my global array history:
void store_history( char *line )
{
if (history_count < 5) {
history[history_count++] = strdup( line );
} else {
for (unsigned index = 1; index < 5; index++) {
history[index - 1] = history[index];
}
history[4] = strdup( line );
}
if (cmdcount < 5){
cmdcount++;
}
}
The error is stemming from my passing the *lines argument in the function, but I can't fathom why. cmdcount is a global variable that counts the number of elements of history to print later (if less than 5). Rest of my code doesn't seem to have any errors. I ran the shell successfully without the history function.
In lsh_loop, the declaration char *line; declares line to be a pointer to a char. So *line is a char.
Then store_history(*line); attempts to pass this char to store_history.
store_history is declared with void store_history( char *line ), which declares its parameter to be a pointer to a char.
A char is not a suitable argument to pass for a parameter that is a pointer to a char, so the compiler reports an error.
To pass the command line to store_history, change the call to store_history(line);.
I'm trying to understand what is wrong here.
void longestConsec(char* strarr[], int n) {
for(int i=0; i<n; i++)
{
printf("%s\n",strarr[i]);
}
}
int main()
{
char string[8][14] = {"zone", "abigail", "theta", "form", "libe", "zas", "theta", "abigail"};
longestConsec(string, 8);
return 0;
}
I want to print every single word, and for some reason it doesn't work. What I think of is that strarr is array of pointer to char, so in every cell there should be a word, right? But when i tried to debug the code i saw that strarr and strarr[0] have different memory locations. Why?
strarr is an array of pointers to char, but string is not an array of pointers but an array of 14-element array of chars.
Pointers and 14-element array of chars may have different size, so your code won't work well.
How about using array of pointers like this?
#include <stdio.h>
void longestConsec(const char* strarr[], int n) {
for(int i=0; i<n; i++)
{
printf("%s\n",strarr[i]);
}
}
int main()
{
const char* string[8] = {"zone", "abigail", "theta", "form", "libe", "zas", "theta", "abigail"};
longestConsec(string, 8);
return 0;
}
Your compiler should have given you a warning that gives a good hint.
k.c:12:19: warning: passing argument 1 of ‘longestConsec’ from incompatible pointer type [-Wincompatible-pointer-types]
12 | longestConsec(string, 8);
| ^~~~~~
| |
| char (*)[14]
k.c:2:26: note: expected ‘char **’ but argument is of type ‘char (*)[14]’
2 | void longestConsec(char* strarr[], int n) {
| ~~~~~~^~~~~~~~
string is an array of arrays, char[8][14] and strarr is a pointer to pointer to char, char **. When string is passed to the function it decays to pointer to array of 14 char, char (*)[14]. Passing multidimensional arrays to functions can be tricky, but this works:
// size_t is better than int in this case
void longestConsec(size_t len, char strarr[][len], size_t n)
{
for(int i=0; i<n; i++)
printf("%s\n",strarr[i]);
}
And then call it with:
longestConsec(sizeof string[0]/sizeof string[0][0], // 14
string,
sizeof string/sizeof string[0] // 8
);
Note that you can write sizeof string[0] instead of sizeof string[0]/sizeof string[0][0] but that's because sizeof char is always 1.
Understanding these declarations can be a bit tricky. Just to give a type example of how they are declared:
char (*arr)[10]; // arr is a pointer to array of char of size 10
char *arr[10]; // arr is an array of 10 pointers to char
Related: arrays are not pointers and pointers are not arrays
I'll get to the point. I know this should be simple, but is giving me the runaround.
I am working on a secure local network. I need to take an input (in my case, an IP address) And cipher that address before storing it safely in a database.
I'd like to cipher it into a letter format. Hard to explain, but if you view this code, you should see what I'm trying to accomplish. I've formatted it to accept an input from you, the user, whereas this function will be called in real time in the background when it's working properly.
Ideally, the user would input 12.23.34.45
The function would print KS.SL.LE.EI
#include <stdio.h>
#include <string.h>
#define MAXLEN 16
void cwitch(char *instr[MAXLEN]){
char *nstr = "0123456789";
char *cstr = "DKSLEIANQP";
int count = strlen(instr);
char *output[count];
int i;
for(i = 0; i < count; i++){
if(instr[i] != '\0'){
int t;
for(t = 0; t < count; t++){
if(instr[i] == "."){ /*Do Nothing, Straight Logic - I Know This Is Useless*/ }
else if(instr[i] == nstr[t]) output[i] = cstr[t];
}
}
}
output[count] = 0; //Null Terminate The String
printf("Output: %s\n", output);
}
int main(void){
char *input[500];
printf("Enter Address: ");
fgets(input, sizeof(input), stdin);
input[strlen(input) - 1] = 0; //Remove \newline Character
cwitch(input);
return 0;
}
However, upon execution, I'm clearly not getting the desired results, or I wouldn't be here!
[root#RyM ~]# ./test
Enter Address: 12.23.34.45
Output:
`
[root#RyM ~]# ./test
Enter Address: 167.174.12.178
Output:
[root#RyM ~]# ./test
Enter Address: 45.223.6.1
Output:
`
[root#RyM ~]# ./test
Enter Address: 918.6.56.222
Output:
[root#RyM ~]#
Any help/advice is appreciated. I'm new into C. Expect warnings when compiling this. Feel free to roast/advise me, pertaining to said warnings existence.
Edit: Warnings included below
[root#RyM ~]# gcc -o test Test.c
Test.c: In function ‘cwitch’:
Test.c:10: warning: passing argument 1 of ‘strlen’ from incompatible pointer type
/usr/include/string.h:399: note: expected ‘const char *’ but argument is of type ‘char **’
Test.c:19: warning: comparison between pointer and integer
Test.c:19: warning: assignment makes pointer from integer without a cast
Test.c: In function ‘main’:
Test.c:31: warning: passing argument 1 of ‘fgets’ from incompatible pointer type
/usr/include/stdio.h:626: note: expected ‘char * __restrict__’ but argument is of type ‘char **’
Test.c:32: warning: passing argument 1 of ‘strlen’ from incompatible pointer type
/usr/include/string.h:399: note: expected ‘const char *’ but argument is of type ‘char **’```
The main problem in your code is a wrong definition of char array (or const string).
A correct definition would be:
char output[count]; // where count is compile time constant
and NOT char *output[count];
the [] tells the compiler this is an array (which is a type of pointer).
Thus, no need to use *, unless you want to define an array of pointers (which is not your case).
here is a cleaned-up code: * Note: this code is far from being perfect or even good, I merely made small changes in order to make it compile and work. *
#include <stdio.h>
#include <string.h>
#define MAXLEN 16
void cwitch(const char* instr) {
const char* nstr = "0123456789";
const char* cstr = "DKSLEIANQK";
int count = strlen(instr);
char output[MAXLEN];
int i;
for (i = 0; i < count; i++) {
if (instr[i] != '\0') {
int t;
for (t = 0; t < count; t++) {
if (instr[i] == '.') {
output[i] = '.';
}
else if (instr[i] == nstr[t]) output[i] = cstr[t];
}
}
}
output[count] = 0; //Null Terminate The String
printf("Output: %s\n", output);
}
int main(void) {
char input[500];
printf("Enter Address: ");
fgets(input, sizeof(input), stdin);
input[strlen(input) - 1] = 0; //Remove \newline Character
cwitch(input);
return 0;
}
In this line
void cwitch(char *instr[MAXLEN])
you are saying that cwitch accepts an array of character pointers (of MAXLEN length). It should just be char *instr. Similar, in this line
char *output[count];
you are declaring an array of char *, while you intend it to be an array of char: char output[count]. Finally, you cannot compare a character 'x' to a string
if (instr[i] == ".")
-- it must be a character literal again ('.').
A small logic problem: if the input character is . you must not "do nothing", you must copy it to the output string as well.
With these fixes your program actually works.
main() {
char names [5][20] = {
"rmaesh",
"ram",
"suresh",
"sam"
"ramu"
};
char *t;
t = names[2];
names[2] = names[3];
names[3] = t;
printf(" the array elemsnt are \n");
int i = 0;
for (i = 0; i < 5; i ++)
printf("\n%s", names[i]);
}
i am getting below error while compiling this program
stringarrary.c: In function ‘main’:
stringarrary.c:12:11: error: incompatible types when assigning to type ‘char[20]’ from type ‘char *’
names[2] = names[3];
^
stringarrary.c:13:11: error: incompatible types when assigning to type ‘char[20]’ from type ‘char *’
names[3] = t;
It is illegal to try and assign to an array. In this case you should use the strcpy function. Note that your char *t; idea does not work either if you intend to swap the two arrays, because it only points at one of your existing strings; as soon as you write over names[2], that data is gone.
char t[20];
strcpy(t, names[2]);
strcpy(names[2], names[3]);
strcpy(names[3], t);
Also, "\n%s" should be "%s\n" - you want the newline to come after what you printed. And don't forget to #include <stdio.h> and #include <string.h>.
The error on line 13 is easiest to understand: names[3] is an array of char; you can't just assign a pointer to it. On line 12, the compiler is converting names[3] to a pointer and trying to assign it to the array names[2], which is likewise can't do.
Try copying the strings instead. In C, you can't copy arrays using the = operator; use the functions from memcpy or strcpy families.
The names array is a two-dimensional array of characters. As the other answers have pointed out, when you want to copy an array of characters, you need to use memcpy or strcpy.
The alternative solution is to make names a one-dimensional array of pointers. The resulting code would look like this.
int main( void )
{
char *names[5] = {
"rmaesh",
"ram",
"suresh",
"sam",
"ramu"
};
char *t;
t = names[2];
names[2] = names[3];
names[3] = t;
printf(" the array elemsnt are \n");
int i = 0;
for (i = 0; i < 5; i ++)
printf("\n%s", names[i]);
}
The advantage to this method is that it allows you to manipulate the pointers the way you wanted to. The disadvantage is that the strings are read-only. Attempting to modify the strings will result in undefined behavior.
Try this
#include<stdio.h>
#include <string.h>
main() {
char names [5][20] = {
"rmaesh",
"ram",
"suresh",
"sam", //<----- You are missing this (,) at the end
"ramu"
};
char *t;
strcpy( t, names[2]); // And also use this syntax
strcpy(names[2] , names[3]);
strcpy(names[3], t);
printf(" the array elemsnt are \n");
int i = 0;
for (i = 0; i < 5; i ++)
printf("\n%s", names[i]);
}