Program crashes when I give printf a pointer to a char array - c

When I try to run the following code I get a seg fault. I've tried running it through gdb, and I understand that the error is occurring as part of calling printf, but I'm lost as to why exactly it isn't working.
#include <stdlib.h>
#include <stdio.h>
int main() {
char c[5] = "Test";
char *type = NULL;
type = &c[0];
printf("%s\n", *type);
}
If I replace printf("%s\n", *type);
with printf("%s\n", c); I get "Test" printed as I expected. Why doesn't it work with a pointer to the char array?

You're passing a plain char and printf is trying to dereference it. Try this instead:
printf("%s\n", type);
^
If you pass *type it's like telling printf "I've got a string at location T".
Also type = &c[0] is kind of misleading. Why don't you just:
type = c;

Don't dereference type. It must remain a pointer.

Remove the dereferencing of type in your printf.

Related

execv arguments error - "expected char * const* but argument is of type const char *"

I have a function whose argument is const char *array[]
array[0] is the path, the rest are the arguments and it ends with NULL.
However, if I try to do execv(array[0], array) I get expected char * const* but argument is of type const char *
How do I go about this, and what is the difference between char * const* and const char *?
void start(const char *array[]) {
execv(array[0], array);
}
First, the error message is not copied correctly. If I run your code in GCC it shows this message instead (note the final *):
note: expected ‘char * const*’ but argument is of type ‘const char **’
which makes more sense as the message you show in the question, does not match the code you show. There is a mismatch in level or indirection.
That said, let's look at this part:
and what is the difference between char * const* and const char *?
Actually it is
and what is the difference between char * const* and const char **?
The first is a pointer to a const pointer to a char. The char that is pointed to is not const and might in theory be changed by execv.
The latter is a pointer to a pointer to a const char. This means, the char that is pointed to mustn't be modified. It might be some read-only string literal in ROM. If you pass such a pointer to a function that will try to modify it, it will fail in one way or the other. Therefore you are not allowed to pass a "pointer to const" to a function that does not expect it to be const.
That is what the compiler is telling you.
Now, how can you get rid of that warning...
To silence your compiler you could try to use some cast and cheat about real nature of that parameter.
In the end the problem will stay the same. A function trying to modify your read-only memory will not be working properly.
Instead you need to make a copy of your data:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void start(const char *array[]) {
int i = 0;
// determine number of strings (including NULL)
while (array[i++] != NULL) ;
// Create an array able to hold pointers to copys
char *my_array[i];
// Copy strings into non-const memory
i = 0;
do
my_array[i] = array[i] ? strdup(array[i]) : NULL;
while (array[i++] != NULL);
execv(my_array[0], my_array);
// Free the memory for the copied strings
i = 0;
do
free(my_array[i]);
while (array[i++] != NULL);
}
int main(void)
{
const char *argv[] = {"ls", "ls", NULL};
start(argv);
return 0;
}

How do I loop over a char pointer in C?

I am trying to access all elements of this preinitialized char pointer in 'c'. Here is the code:
#include <stdio.h>
#include <stdlib.h>
void main()
{
char **s="Hello";
printf("%c",*(*&s+1));
}
This code should output "e", but doesn't. What am I doing wrong?
Also, how do I access all elements one by one?
The type of s is incorrect. The string constant "Hello" has array type which can decay to type char * but you're assigning it to a variable of type char **.
Change the type of s to char * and your code will output "e":
char *s = "Hello";
Also, looking at this:
*(*&s+1)
When * comes right before & they cancel each other out. So you can simplify this to:
*(s+1)
Or equivalently:
s[1]
Assumed that you are not seeing the 'e' of the Hello, I highly recommend watching this post.
What to do when the pointer doesn't print the string properly
Just to summarize, when you reference the pointer s, it is only reading the H of Hello (since that is how the pointer of string works - it points to the first character of the string, like s[0]), and that results your code in printing out H only.
Most importantly, your pointer is double-pointer, which is incorrect.
Try it in this way.
#include <stdio.h>
#include <stdlib.h>
void main()
{
char s[] = "Hello";
printf("%s\n",s);
}

c: strtod: double pointer vs. reference to single pointer

Works great.
#include <stdio.h>
#include <stdlib.h>
int main(void){
char number[]= "a123.45", *strtod_eptr;
double num;
num=strtod(number, &strtod_eptr);
if (strtod_eptr == number){
printf("Error: no number found.\n");
}
else{ printf("%f\n", num+7);
}
return 0;
}
Does not work. Second argument in strtod() changed type.
#include <stdio.h>
#include <stdlib.h>
int main(void){
char number[]= "a123.45", **strtod_epptr;
double num;
num=strtod(number, strtod_epptr);
if (*strtod_epptr == number){
printf("Error: no number found.\n");
}
else{
printf("%f\n", num+7);
}
return 0;
}
Compiler warns about uninitialized strtod_epptr but no compile errors.
strol_test.c:7:5: warning: ‘strtod_epptr’ is used uninitialized in this function [-Wuninitialized]
Program crashes (seg fault) at the if() statement.
Compiler command (in both cases):
gcc -Wall -pedantic -o "strol_test" "strol_test.c"
Why does this happen? Why does gcc complains about uninitialized **strtod_epptr while being totaly fine with (similarily uninitialized ?) *strtod_eptr ?
And what goes wrong when dereferencing **strtod_epptr? AFAIK:
char *ptr;
...strtod(...,&ptr)
should be the same as
char **ptr;
...strtod(...,ptr)
but obviously it is not. What am I missing?
Think about memory.
When you write char *str you asked the compiler to allocate memory for a char pointer. Now when you send the address of str to a function, as &str that value inside str can be changed.
Now the other way around.
When you write char **str you asked the compiler to allocate memory for a pointer to a char pointer. That means there is NO memory allocation for the char pointer. If you dereference that pointer now, it will point to nothing meaningful.
Now, you passed str to strtod(). The function now does *str = something(). BUT that place does not exist in the memory. That bucket was not created and allocated.
In the future, always pass the ADDRESS of an already existing variable. If not, there is no variable the function can update...
strtod expects a double-pointer (pointer to pointer), because it wants to tell
the user the location where it stopped reading. So it has to change where a
pointer is pointing, thus it cannot take a (single) pointer, it has to take a
pointer to a pointer.
man strtod
#include <stdlib.h>
double strtod(const char *nptr, char **endptr);
[...]
RETURN VALUE
These functions return the converted value, if any.
If endptr is not NULL, a pointer to the character after the last character used in the conversion is stored in the location referenced
by endptr.
That means that the pointer you pass through endptr must point to a valid
char-pointer, that's why
char number[]= "a123.45", *strtod_eptr;
num=strtod(number, &strtod_eptr);
works well because &strtod_eptr returns the address of the strtod_eptr
variable, it returns a pointer to a pointer. strtod can then use the pointer
to a pointer to change where the original pointer (strtod_eptr) will
point.
Internally strtod will do something like this:
double strtod(const char *nptr, char **endptr)
{
size_t i;
double converted_value;
...
if(endptr != NULL)
{
// i is the index the character after the last
// character used in the conversion
*endptr = &(nptr[i]);
}
return converted_value;
}
When endptr points to a valid location, dereferencing it won't be a problem.
However
char number[]= "a123.45", **strtod_eptr;
num=strtod(number, strtod_eptr);
doesn't work, because strtod_eptr is an uninitialzed pointer that points
to nowhere in particular. When strtod does *endptr = &(nptr[i]), it is
trying to write a value in an undefined memory location, this is undefined behaviour and the
segfault is a manifestation of that.
This would work however:
char number[]= "a123.45", *end, **strtod_eptr;
strtod_eptr = &end;
num=strtod(number, strtod_eptr);
Because in this case strtod_eptr would point to a valid location.

working with char pointer and integer pointer

My question is about dereferencing a char pointer
Here is my code -
#define MAX 10
char s[80]="Hello";
int main(){
char *stackValue;
stackValue=&s;//here I assined the address of s to stackValue
if(!stackValue){
printf("No place for Value");
exit(1);
}
else{
printf("\n%s",*stackValue);//This doesn't work with * before it
printf("\n%s",stackValue);//This works properly
}
return 0;
}
In the above code I have assigned the address of S[] to stackValue and when I am printing *stackValue it doesn't work ,
But If I print only 'stackValue' That works.
When I do same thing with Integer
int main(){
int i=10, *a;
a=&i;
printf("%d",*a);//this gives the value
printf("%d",a)//this gives the address
return 0;
}
Is printing char pointer and integer pointer is different. When I use * in int value it gives the value but gives an error when I use it as a char pointer.
Help me out?
With the first code snippet:
stackValue=&s; is incorrect given s is already an array to char. If you write like that then stackValue becomes pointer to pointer to char (not pointer to char).
Fix that by changing to stackValue=s;
Also, again %s expect a pointer to char (NOT pointer to pointer to char) - that explains why this doesn't work
printf("\n%s",*stackValue); // this doesn't work
You need printf("\n%s",stackValue); instead.
With the second code snippet.
a=&i; is ok because i is a single int, NOT an array.
What you are trying to do is this:
int main(void)
{
char a_data = "Hello, this is example";
char *pa_stack[] = {a_data};
printf("We have: %s\n", *pa_stack);
}
The "%s" format specifier for printf always expects a char* argument.
so this is working and correct statement
printf("\n%s",stackValue);
and in first statement you are passing value so it will give you undefined behaviour.

Why do pointers behave differently with ints vs strings in C

I'm learning C right now and am trying to understand why the first snippet of code below works but the second one doesn't.
Here I create a char* and assign a string to it (this works fine):
int main(void)
{
char *s = malloc(strlen("Hello!") + 1);
s = "Hello!\0"; //Why am I able to do this without dereferencing (i.e., *s)?
printf("%s\n", s); //Why don't I need to dereference s here?
}
Here I create an int* and assign a value to it (this one doesn't work):
int main(void)
{
int *i = malloc(sizeof(int));
i = 5; //I get that this doesn't work because I'm not dereferencing i. Why does the above code with 's' not have the same issue?
printf("%i\n", i); //I also understand what the issue is here. What confuses me is why the printf above doesn't have the same issue.
}
For i = 5 vs. s = "Hello!", I'm guessing there's some difference in how string literals are passed vs ints (but I'm not completely sure what it is).
For the two different uses of printf, I'm a bit more confused. If I pass s to printf, shouldn't it just print out the address of s rather than the actual string?
int main(void)
{
char *s = malloc(strlen("Hello!") + 1);
s = "Hello!\0"; //Why am I able to do this without dereferencing (i.e.,*s)?
printf("%s\n", s); //Why don't I need to dereference s here?
}
This will work with integers:
int main(void)
{
int *i = malloc(sizeof(int));
i = (int *) 5; //I get that this doesn't work because I'm not dereferencing i. Why does the above code with 's' not have the same issue?
printf("%i\n", (int) i); //I also understand what the issue is here. What confuses me is why the printf above doesn't have the same issue.
}
You just need the casts because 5 is not a pointer while "Hello!\0" is. In both cases, you just throw away the return value of malloc because you set the pointer to point to something else.
So the short answer is that they don't behave differently. You're just using matching types in one case (s is a pointer to char and "Hello!\0" is convertible to a pointer to char) and mismatched types in the second (5 is an integer while i is a pointer to an integer).

Resources