Here's more code I whipped up since i was having trouble with my major program that I now fixed.
I have a function which modifies a series of bytes. In this example, the function is supposed to fill up the first 9 bytes of the char array with the numbers 1 through 9 consecutively.
Two tests are run. The first one is calling the function where the parameter is (char*)&myvar. The second test only uses myvar as a parameter. I thought I always had to use an & in front of a char array pointer when I want the string returned in the parameter portion of the function.
Why does this program only work when I don't prepend (char*)& to my char array variable?
When I do apply it, I receive a segmentation fault.
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
int func(char* abc){
char *p=abc;
int n;
for (n=1;n<10;n++){
*p=(unsigned char)(n+48);p++;
}
return 0;
}
int main(){
char vars[1000]="234";
char *myvar=vars;
printf("Function test\n");
int result=func((char*)&myvar); //causes segfault
printf("Function result %s\n",myvar); //segfault here
printf("Function test again\n");
int result2=func(myvar); //works
printf("Function result %s\n",myvar);
printf("DONE\n");
return 0;
}
Why does this program only work when I don't prepend (char*)& to my char array variable?
Because doing that is completely wrong and not a thing that makes sense.
I thought I always had to use an & in front of a char array pointer when I want the string returned in the parameter portion of the function.
You don't. (Also, you do not have a "char array pointer", and "when I want the string returned in the parameter portion of the function" doesn't make sense.)
When you need to pass a char * to a function that takes a char *, you do not need to put any special prefix in front of the pointer. You just pass it directly, the way you did with
int result2=func(myvar);
You could also have passed in vars, due to the automatic conversion from an array to a pointer to its first element, just like you were able to do char *myvar=vars; without any special casting.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I have this code:
char** SplitToWords(char* str);
int main()
{
char** wordarr;
char str[] = "This is a sentence";
wordarr = SplitToWords(str);
return 0;
}
After the main comes the function implementation.
I am not sure the following does what I want it to do (i.e. receive an array of strings from a function):
wordarr = SplitToWords(str);
I somehow managed to convince the compiler that it's ok, but I assume it just does something else.
If it does, how do I find out the length of the array (the number of strings in it).
Thanks
I'll try to quickly visit all aspects you might not yet fully understand:
A string in C is described as a contiguous sequence of chars, ending with a char of value 0 (as a literal: '\0'). It is not a first class object, therefore hasn't its own type. So what you use to hold a string is an array of char. Therefore, taking your question by the word, "receive an array of strings from a function" is not possible.
An array is a contiguous sequence of objects of the same type. In C, the identifier of an array doesn't have a value itself; when it's evaluated, it decays as a pointer to the array's first element instead. This is especially important when passing arrays to functions or returning them from functions -- you can't actually pass the array, you always pass a pointer
e.g. you could write:
char x[] = "foo"; // initialize a char array from a string literal
char *xp = x; // here, x evaluates as a pointer to the first element of the array
You already use pointer types for your function's argument and return value, I just think it's quite important to understand what happens entirely.
You write char** SplitToWords(char* str); and ask whether this returns an "array of strings" -- well, sort of, as you should understand after reading 1. and 2. -- What it does is returning a pointer to char *. This pointer could be a pointer to the first element of an array. So in this case, it would return a pointer to an array of char * pointers. Each of these pointers could itself be a pointer to an array of chars, therefore point to a string. But what's very important is to understand you never return an array, you always return a pointer to it. It's so important because:
You might get the idea to do something like this:
char** SplitToWords(char* str)
{
char *words[16];
// code to fill `words` with pointers to the actual words
return words; // WRONG!
}
Here, because you're not returning the array words but a pointer to it (see point 2), you return a pointer to an object that no longer exists. words is in the scope of your function and has automatic storage duration, that means it only lives as long as the execution is inside of the function. One solution would be to declare words with the static storage class specifier. This way, it lives for the entire execution time of the program. But be aware that this also means there's only a single instance ever, it's always the same object. This will be a major headache for threaded programs, for example. The other way around is to dynamically allocate words using malloc(). But then, the caller of the function must free() it later.
As for your second question, how to let the caller know the number of words -- it's in the comments already, but just for completeness, a typical approach to solve this is to append another entry that is a NULL pointer. So the caller can iterate over the pointers until it finds NULL.
Regarding your comment, of course you can create the array outside the function and pass a pointer to the function, so the function only fills it. This is a common idiom in C (e.g. think about fgets(), which takes a pointer to the char array that's filled with a string by the function).
Functions working this way will need an additional size_t parameter, so they know the size of the array they should fill through the pointer, otherwise you'd have the risk of buffer overflows (this is why gets() was finally removed from the C standard). If you decide that the caller provides the storage, your function should have this prototype:
// returns the number of words found, up to `nwords`
size_t SplitToTwords(char **words, size_t nwords, char *str);
It should be called e.g. like this:
char *words[16];
size_t nwords = SplitToWords(words, 16, "the quick brown fox"); // returns 4
Remember that the strings holding the words themselves need storage as well. You can either manipulate the bytes in str to insert a '\0' after each word, overwriting the first whitespace character (this is what strtok() does) or you can copy the words to new strings, but then you would have to malloc() each of them again and the caller has to free() them later.
Yes, you could solve it by using a function with return value char **. However, there's no way to find out how many words there are afterwards.
You can solve this by allocating one more element for the return pointer and set it to NULL. Then you can get the number of words with this code:
wordarr = SplitToWords(str);
char **ptr=wordarr;
int noWords=0;
while(!*(ptr+noWords))
noWords++;
But if you want to return multiple data in C, you either need to define a return struct or using return arguments. In this case, it could look like this for the first option:
typedef struct wordList {
char **wordarr;
int noWords;
}
wordList SplitToWords(char* str);
And the second:
char** SplitToWords(char* str, int *noWords);
or
void SplitToWords(char* str, char*** wordarr, int *noWords);
Note that there's three *. That's because we want it to be a pointer to char **
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXSTRINGS 5000
int main(int argc, char *argv[]) {
char *stringTable[MAXSTRINGS];
char sentence[] = "This is a sentence";
char *token = NULL;
int i = 0;
while ((token = strtok(token == NULL ? sentence : NULL, " ")) != NULL)
{
printf("%s\n\r", token);
stringTable[i] = (char *)malloc(strlen(token) + 1); //have no "plain" C compiler - VS C++ used so cast needed :)
strcpy(stringTable[i++], token);
}
stringTable[i] = NULL; // if you need to iterate through later
printf("%d tokens found\n\r", i);
for (int y = 0; y < i; y++)
free(stringTable[y]);
}
I expected to get errors in following code, but I did not. I did not use & sign. Also I am editing array of chars.
#include <stdio.h>
int main()
{
char name[10] ="yasser";
printf("%s\n",name);
// there is no error ,
// trying to edit array of chars,
// also did not use & sign.
scanf("%s",name);
// did not use strcpy function also.
printf("%s\n",name);
return 0;
}
I expected to get errors in following code, but I did not.I did not use & sign.
scanf("%s",name);
That's totally ok as name is already the address of the character array.
It sounds like you have several questions:
calling scanf("%s", name) should have given an error, since %s expects a pointer and name is an array? But as others have explained, when you use an array in an expression like this, what you always get (automatically) is a pointer to the array's first element, just as if you had written scanf("%s", &name[0]).
Having scanf write into name should have given an error, since name was initialized with a string constant? Well, that's how it was initialized, but name really is an array, so you're free to write to it (as long as you don't write more than 10 characters into it, of course). See more on this below.
Characters got copied around, even though you didn't call strcpy? No real surprise, there. Again, scanf just wrote into your array.
Let's take a slightly closer look at what you did write, and what you didn't write.
When you declare and initialize an array of char, it's completely different than when you declare and initialize a pointer to char. When you wrote
char name[10] = "yasser";
what the compiler did for you was sort of as if you had written
char name[10];
strcpy(name, "yasser");
That is, the compiler arranges to initialize the contents of the array with the characters from the string constant, but what you get is an ordinary, writable array (not an unwritable, constant string constant).
If, on the other hand, you had written
char *namep = "yasser";
scanf("%s", namep);
you would have gotten the problems you expected. In this case, namep is a pointer, not an array. It's initialized to point to the string constant "yasser", which is not writable. When scanf tried to write to this memory, you probably would have gotten an error.
When you pass arrays to functions in C, they decay to pointers to the first item.
Therefore for:
char name[] ="yasser";
scanf("%s", name) is the same as scanf("%s", &name[0]) and either of those invocations should send shivers down your spine, because unless you control what's on your stdin (which you usually don't), you're reading a potentially very long string into a limited buffer, which is a segmentation fault waiting to happen (or worse, undefined behavior).
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv, char **envp) {
char *myName = (char *) calloc(10, sizeof(char));
*(myName)='K'; *(myName+1)='h'; *(myName+2)='a'; *(myName+3)='l'; *(myName+4)='i'; *(myName+5)='d';
printf("%s\n",myName);
scanf("%s",myName);
printf("%s\n",myName);
return (EXIT_SUCCESS);
}
#include <stdio.h>
#include <string.h>
int main()//fonction principale
{
char name[10] ="yasser";
int longeur=0;
printf("%s\n",name);
scanf("%s",name);
longeur = strlen(name);
for (int i=0;i<longeur;i++) {
printf("%c",*(name+i));
}
return 0;}
This question already has an answer here:
Pointer losing its value + execv compilation warning
(1 answer)
Closed 7 years ago.
my original problem is that I want to write a function that can return me two values. I know that I can do it by passing the address of the two arguments to the function, and directly calculate their values inside that function. But when doing experiment, something weird happens. The value I got inside the function cannot survive to the main function:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void build(char *ch){
ch = malloc(30*sizeof(char));
strcpy(ch, "I am a good guy");
}
void main(){
char *cm;
build(cm);
printf("%s\n", cm);
}
The above program just prints out some garbage. So I want to know what's wrong here. Eventually, I want something like this parse(char **argv, char **cmd1, char **cmd2), which can parse out two commands for me from the original command argv. That would be great if anybody can explain a little bit. Thanks a lot.
build() take the pointer ch by value, i.e. a copy of the pointer is passed to the function. So any modifications you make to that value are lost when the function exits. Since you want your modification to the pointer to be visible in the caller's context, you need to pass a pointer to pointer.
void build(char **ch){
*ch = malloc(30*sizeof(char));
strcpy(*ch, "I am a good guy");
}
Also, you don't need to pass pointers to a function because you need to return multiple values. Another option is to create a struct that contains the values you wish to return as members, and then return an instance of said struct. I'd recommend this approach over the first if the values are related and it makes sense to package them together.
Here's a re-listing of your code after fixing bugs:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void build(char **ch){
*ch = malloc(30 * sizeof(char));
strcpy(*ch, "I am a good guy");
}
int main() { // main must return int
char *cm;
build(&cm); // pass pointer to pointer
printf("%s\n", cm);
free(cm); // free allocated memory
return 0; // main's return value, not required C99 onward
}
If you want to malloc inside the function, you need to pass the address to the outside pointer since ch inside the function is only a local variable, and changing it doesn't affect the outside cm variable
void build(char **ch){
*ch = malloc(30*sizeof(char));
strcpy(*ch, "I am a good guy");
}
void main(){
char *cm;
build(&cm);
printf("%s\n", cm);
}
But better don't malloc inside the function, instead just write what you want to the area pointed to by the pointer. This is the common way when you need to provide a buffer to get data in C. In this way users will have the choice to allocate memory their own, or just use a local buffer and don't need to free memory after that like you've just forgotten in your example
void build(char *ch){
strcpy(ch, "I am a good guy");
}
void main(){
char *cm1;
cm1 = malloc(30*sizeof(char));
build(cm1);
printf("%s\n", cm1);
char cm2[30];
build(cm2);
printf("%s\n", cm2);
free(cm1); // don't forget this
}
This is because in C, you cannot reassign the memory address of the pointer because it is passed by value.
If you really want to do this, you must pass the address of the pointer into the build function.
See: Passing pointer argument by reference under C?
The following C program attempts to fetch and print the host name of the current RHEL host. It throws a segmentation fault on this machine. As per the definition of gethostname I should be able to pass a char pointer, shouldn't I?
When I use a char array instead (like char hname[255]), the call to gethostname works. (If I did this how would I return the array to main?)
#include <stdio.h>
#include <unistd.h>
char * fetchHostname()
{
// using "char hname[255]" gets me around the issue;
// however, I dont understand why I'm unable to use
// a char pointer.
char *hname;
gethostname(hname, 255 );
return hname;
}
int main()
{
char *hostname = fetchHostname();
return 0;
}
Output:
pmn#rhel /tmp/temp > gcc -g test.c -o test
pmn#rhel /tmp/temp >
pmn#rhel /tmp/temp > ./test
Segmentation fault
pmn#rhel /tmp/temp >
As gethostname man said:
The gethostname() function shall return the standard host name for
the current machine. The namelen argument shall
specify the size of the array pointed to by the name argument.
The returned name shall be null-terminated, except that
if namelen is an insufficient length to hold the host name,
then the returned name shall be truncated and it is
unspecified whether the returned name is null-terminated.
You need a place to store the function information, so declare hostname as an array, not a pointer.
#include <unistd.h>
char * fetchHostname(char *hostname, int size)
{
// using "char hname[255]" gets me around the issue;
// however, I dont understand why I'm unable to use
// a char pointer.
gethostname(hostname, size);
return hostname;
}
int main()
{
char hostname[HOST_NAME_MAX + 1];
fetchHostname(hostname, HOST_NAME_MAX);
return 0;
}
When I use a char array instead (like char hname[255]), the call to
gethostname works. (If I did this how would I return the array to
main?)
By passing a pointer to the array from main() to your function. Note that this approach makes your function fetchHostname() to be just a wrapper for function gethostname():
#include <stdio.h>
#include <unistd.h>
void fetchHostname(char *hname)
{
gethostname(hname,255);
}
int main()
{
char hostname[256];
fetchHostname(hostname);
return 0;
}
Or by declaring your hname[] array local static, so it is valid even after the program leaves the function (this approach is not thread-safe):
#include <stdio.h>
#include <unistd.h>
char *fetchHostname (void)
{
static char hname[256];
gethostname(hname,255);
return hname;
}
int main()
{
char *hostname;
hostname = fetchHostname();
return 0;
}
Though there are many technically correct answers I don't think that they actually explain to you where you went wrong.
gethostname(char *name, size_t len); is documented here and it basically says that the parameter name is an array of characters that you have allocated where this function will copy the hostname into. And how you do that is explained in the many other wonderful answers here.
That is why this works if you make the array yourself but causes a segmentation fault if you just give it a pointer.
Also, you were giving this function an uninitialized pointer so when it tried to copy data to that address (which is just some completely random place in memory) it caused your program to terminate because it was trying to write a string where it isn't allowed to.
This type of mistake tells me that you need to brush up on what pointers actually are and that you need to understand that they can be used to allow a function to return a value in a different way than using the return statement.
Update: please see #Tio Pepe's answer.
You need to allocate space in your array (either statically or dynamically):
char hname[HOST_NAME_MAX + 1];
otherwise you are passing an uninitialised pointer that could point anywhere.
Your call to gethostname():
gethostname(hname, 255);
is a contract that says here is a pointer that points to at least 255 characters of allocated space.
Also, you are trying to return a pointer to space allocated on the stack. That's not good.
Yoi need to dynamically allocate the character array if you want to return it.
char * hname;
hname = malloc((HOST_NAME_MAX +1) * sizeof(char));
But be aware that you now have to manage when that space gets freed.
Returning a pointer to a local variable is undefined behavior, because it will go out of scope. If you allocate it on the heap (via dynamic allocation), you will not have this problem.
char * fetchHostname()
{
char* hname= malloc(sizeof(char) * 256);
gethostname(hname, 255);
return hname;
}
int main()
{
char *hostname = fetchHostname();
printf(hostname);
free(hostname);
return 0;
}
char *hname; //defined inside a function and would be destroyed after the function is executed
After the execution of fetchHostname() the address returned to the hostname is not valid and acessing it would result in segmentation fault
I am trying to read a large list of English words from a text file to array of strings. The number of words is 2016415, and maximum length of a word is 69 characters.
If I define array like "char data[2016415][70]; " then I get stack overflow when I run the program.
So I am trying to use calloc() instead, however I can't understand how should I type-cast it so that it becomes equivalent to "char data[2016415][70];".
The following program returns "passing arg 1 of `fgets' makes pointer from integer without a cast" warning during compiling. And when I execute it, it gets "Exception: STATUS_ACCESS_VIOLATION" problem.
Can you help me?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void){
char *data; //data[2016415][70];
int i;
FILE *fsol;
fsol = fopen("C:\\Downloads\\abc\\sol2.txt","r");
data = (char*) calloc(2016415,70);
for(i=0;i<2016415;i++){
fgets(data[i] , 70 , fsol);
}
fclose(fsol);
return 0;
}
calloc just allocates a big swath of memory - not an array of pointers to other arrays.
fgets expects a pointer to the memory location it should dump it's stuff at.
So instead of giving it the contents of data[i], you want to give it the address of data[i] so it can put its stuff there.
fgets(&data[i], 70, fsol);
You'll probably also need to adjust your loop so that it goes up by 70-odd characters at a time rather than one.
Okay, sorry about the previous suggestion. I forgot how horrible arrays can be. This one is tested with a small data set of 10 words, but it should scale to your word count. Note that fgets() seems to pull in the line endings as part of the preceding word.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_WORD_CNT 2016415
#define MAX_WORD_LEN 70
int main(void)
{
char *data; //data[2016415][70];
int i;
FILE *fsol;
fsol = fopen("C:\\Downloads\\abc\\sol2.txt","r");
data = (char*) calloc(MAX_WORD_CNT, MAX_WORD_LEN);
// check for valid allocation
if (data == NULL)
{
return 1;
}
for(i=0; i<MAX_WORD_CNT; i++)
{
fgets(&data[i * MAX_WORD_LEN], MAX_WORD_LEN, fsol);
}
fclose(fsol);
return 0;
}
Here's how I would allocate the array
char **data = malloc(MAX_WORD_CNT * sizeof(char *));
for(int i = 0; i < MAX_WORD_CNT; i++)
data[i] = malloc(MAX_WORD_LEN);
you might want to add some error checking for malloc though.
data is a pointer to char (also addressable as an array of char), so data[i] is a single char. fgets expects a pointer to char but you're passing it a single char; that's why you're getting the warning, you're trying to use a char (integer) as a pointer.
When you run the program, it then takes that single char argument and interprets it as a pointer to char, hence the access violation because the value of that char is not a valid address.
So, in your loop you should pass fgets a pointer into data and increment that by 70 with each iteration. You can use the "pointer to an array element" form &data[i] and increment i, or the simple pointer form, with another pointer variable initially set to data, and itself incremented.
The answer is simple: you DON'T cast it. Casting the results of malloc/calloc/etc. has no purpose but can have the side-effect of hiding a major bug if you forgot to include stdlib.h. The return type of these allocation functions, which is void *, will automatically be cast to whatever you need.
If you really want to know the type, it's (char (*)[70]). But please don't actually obfuscate your program by writing that. (Unless you're actually writing C++, in which case you should have tagged your question C++ and not C, or better yet used new.)