Extracting string from main() arguments - c

I am trying to create a pointer to one of the main() arguments in my program.
I set up the initial pointer, then I set it equal to the 2nd element in the array, but I get an error when I try to compile, segmentation fault. Does this occur because a pointer is pointing to a bad address?
Here is the code:
char *filename;
*filename = argv[1];
printf("The filename is: %s", *filename);
I get errors about the pointer trying to cast the argument as an int. Is this because the pointer is actually an integer address value and I am trying to set it equal to a string?
Edit: When I change to "filename = argv[1]", then I get the following error from my compiler: assignment discards qualifiers from pointer target type.

A segmentation fault couldn't possibly occur when you compile. Unless, well, the compiler violates memory safety, which is unlikely. I'll take it that it happens when you run the program :D.
The problem is here:
*filename = argv[1];
It should be:
filename = argv[1];
Why? You declared a pointer to char, unitialized, poiting nowhere in particular. Then, you dereferenced that pointer and assigned data to that memory position. Which is, well, who knows where!
Edit: you also dereference filename in the printf() call. Remove that * :).
Also, didnt' the compiler shoot a warning when you assigned *filename? Making integer from pointer without a cast, would be my guess? Pay attention to the warnings, they provide useful information!
Cheers.

You're not making filename point to the same place as argv[1]. To do that you need
filename = argv[1];
With your version (*filename = argv[1];) you're trying to make whatever filename points to have the value that is in argv[1]. There's lots of stuff wrong with this: a) filename is not initialized and can point anywhere, even invalid locations; b) argv[1] is of type char* and you're trying to put it into a location of type char!

In the statement *filename = argv[1];, the expression *filename attempts to dereference (find the value pointed to) the filename pointer, which is not yet pointing anywhere meaningful.
Change the assignment to filename = argv[1].

You're dereferencing the char* when you try to assign it, so you're trying to stuff a pointer into a char. And since filename is uninitialized, you're trying to hit some random address (or perhaps address 0x00000000. And your print statement, if you got that far, wouldn't work either: you're again dereferencing the char* (to get a char) and then telling printf to interpret that as a pointer to a nul-terminated string.
Try this:
char *filename ;
filename = argv[1] ;
printf( "The filename is: %s" , filename ) ;

Related

Why we didn't use * during dereferencing the pointer?

In the below code, we get a pointer from strdup(source) and we store it in a pointer named target.
Now, when we print the string using pointer, we don't add * at the beginning of the pointer: why is it so? As I studied whenever we want to dereference any pointer we use *pointer_name. If we add * in the below code, we get an error.
I am very beginner, so pls ans in easy words.
#include<stdio.h>
#include<string.h>
int main()
{
char source[] = "Programming";
char* target = strdup(source);
printf("%s\n",target);
return 0;
}
printf expects a char pointer in the place of the %s specifier.
https://en.cppreference.com/w/c/io/fprintf
char* target = strdup(source);
printf("%s\n",target);
Why we don't use *target in the code above?
The explanation is quite simple, as already stated in previous answers: target has type char pointer, which is exactly what printf() wants in the above call.
Now, printf() is a little complicated because its semantic is not simple - basically it accepts zero or more arguments after the first, of any type (possibly applying promotion). But if we use strdup() again, maybe it is simpler:
char* target2 = strdup(target);
Here, if you wrote strdup(*target), the compiler might warn that you are passing a char instead of a pointer to char.
strdup() returns a char*, hence the char* type of target. target holds a pointer to the first character in an array of chars. printf("%s", string) expects string to be a char*, so there’s no reason to do anything to target; just pass it to printf().
If you dereferenced target, you would get a single char (P in this case). printf() would then complain that you had supplied a character instead of a string (pointer to character). Even worse, the program could compile, and then printf() would try to print the string at address P (0x50), which would result in probably unwanted behaviour.
When working with arrays—a string is a type of array—you rarely want to dereference the array.

Pointer Pointing to Pointer

Lets say I have a variable:
char** code;
I then do:
*code[0] = "Lucas"
Is it valid to say that, **code holds an array of pointers (*code is the array which I am making strings) and that *code[0] will equal "Lucas" and that *code[0][2] will equal 'c'?
Sorry if it seems elementary, I am getting very confused with double pointers! Thanks in advance!
-Lucas Giancola
Is it valid to say that, **code holds an array of pointers
No it is not. You have allocated space for a single pointer. You have told the compiler that that pointer will point at another pointer (that you have not created yet) that points to a character (that you have not created yet either)
*code[0] = "Lucas"
Is not valid code and doesnt compile
prog.cpp:6:8: error: invalid conversion from 'const char*' to 'char' [-fpermissive]
*f[0] = "Lucas";
If you just have
char** code;
*code[0] = "Lucas";
you'll run into undefined behavior since you did not allocate any memory for code.
You'll need to use:
char** code = malloc(SOME_SIZE*sizeof(*code));
Even after that, using:
*code[0] = "Lucas";
is not good. There are couple of problems with that.
code[0] is a pointer. *code[0] is that pointer dereferenced. If you already have some string in code[0], then, *code[0] will be first character of that string. The assignment is, therefore, wrong.
Also, "Lucas" is going to be in a read-only parts of the compiled code. You will need to make a copy of "Lucas" using strdup before you assign it to a variable that is of type char *.
You need something like:
code[0] = strdup("Lucas");
Now you can use code[0] to access the whole string. You can use *code[0] to access the first character of that string. You can also use code[0][0] to access the first character of that string.

pointer to value in array?

So I need to have a pointer to a value in a const char array. But I can't quite get it to work without errors. Here's the code.
int main (void)
{
const char *alp = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char *ptr = &alp[3];
printf("%s\n", ptr);
return 0;
}
Edit- Sorry for not mentioning the errors. The thing is I get tons of different errors depending on where I put different asterisks and ampersands. There is no one particular error. One of the more frequent ones I get says
"incompatible integer to pointer conversion assigning to 'char *'
from 'const char';"
In the end I just want "ptr" to be equal to a pointer pointing to "D" in the array "alp".
If you only want one character to print, change the %s to %c and dereference the pointer
printf("%c\n", *ptr);
It's true that you had a character pointer but %s tells printf to print from that pointer until it reads a null character. So we switch to %c which will print one character but it expects a value rather than a pointer to a value.
alp is a pointer to constant char.
ptr is a pointer to a non-const char.
If you want that to work out you would need to change ptr to be defined as:
char const * ptr = &alp[3];
The const is saying that you're not going to change it, but then you're trying to copy the reference to a variable without that limitation. Instead, try:
const char *ptr = &alp[3];
But note that as other posters have already suggested, this code will give you a pointer to a string beginning with the D (e.g. DEFGHI...), not just the character D.

How to get a pointer to a string in C using the reference operator?

Is there anyway given a string like, "my example\n", to get a pointer to it? For instance, &"my example\n" or &{"my example\n"}?
EDIT: I guess asking rudimentary questions is what I get for not sleeping last night. Ah well, thanks for all your help anyway.
It's already a pointer:
char *string = "my string\n";
string will be a pointer to the literal string.
It already is an address.
Example: char * addr= "my example\n";
Here, the variable addr holds the address of the string.
To your code, a string constant appears as a pointer; specifically a character pointer char* to the first character in the string.
In order to be more strict: the string literals are of type const char[]. However const char[] can be implicitly casted into const char*. So you can easily obtain the pointer by assigning
const char* p = "string";
Please note that if your next line would be
const char* p1 = "string";
--the value of p1 is not guaranteed to be equal to the value of p: different string constants may have different addresses (but don't need to).
Note that p will be pointer to the first character rather than to the whole string.
Another caveats is that you shouldn't try to get the char* pointer (by casting const away), as this will result in undefined behaviour. For example, the compiler may put the string literal into the read-only memory, and the program will simply crash.

Why am I able to change the contents of const char *ptr?

I passed a pointer ptr to a function whose prototype takes it as const.
foo( const char *str );
Which according to my understanding means that it will not be able to change the contents of ptr passed. Like in the case of foo( const int i ). If foo() tries to chnage the value of i, compiler gives error.
But here I see that it can change the contents of ptr easily.
Please have a look at the following code
foo( const char *str )
{
strcpy( str, "ABC" ) ;
printf( "%s(): %s\n" , __func__ , str ) ;
}
main()
{
char ptr[ ] = "Its just to fill the space" ;
printf( "%s(): %s\n" , __func__ , ptr ) ;
foo( const ptr ) ;
printf( "%s(): %s\n" , __func__ , ptr ) ;
return;
}
On compilation, I only get a warning, no error:
warning: passing argument 1 of ‘strcpy’ discards qualifiers from pointer target type
and when I run it, I get an output instead of Segmentation Fault
main(): Its just to fill the space
foo(): ABC
main(): ABC
Now, my questions is
1- What does const char *str in prototype actually means?
Does this mean that function cannot change the contents of str? If that is so then how come the above program changes the value?
2- How can I make sure that the contents of the pointer I have passed will not be changed?
From "contents of the pointer" in the above stated question, I mean "contents of the memory pointed at by the pointer", not "address contained in the pointer".
Edit
Most replies say that this is because of strcpy and C implicit type conversion. But now I tried this
foo( const char *str )
{
str = "Tim" ;
// strcpy( str, "ABC" ) ;
printf( "%s(): %s\n" , __func__ , str ) ;
}
This time the output is, with no warning from compiler
main(): Its just to fill the space
foo(): Tim
main(): Its just to fill the space
So apparently, memory pointed to by str is changed to the memory location containing "Tim" while its in foo(). Although I didn't use strcpy() this time.
Is not const supposed to stop this? or my understanding is wrong?
To me it seems that even with const, I can change the memory reference and the contents of memory reference too. Then what is the use?
Can you give me an example where complier will give me error that I am trying to change a const pointer?
Thanks to all of you for your time and effort.
Your understanding is correct, const char* is a contract that means you can't change memory through this particular pointer.
The problem is that C is very lax with type conversions. strcpy takes a pointer to non-const char, and it is implicitly converted from const char* to char* (as compiler helpfully tells you). You could as easily pass an integer instead of pointer. As a result, your function can't change content pointed by ptr, but strcpy can, because it sees a non-const pointer. You don't get a crash, because in your case, the pointer points to an actual buffer of sufficient size, not a read-only string literal.
To avoid this, look for compiler warnings, or compile, for example, with -Wall -Werror (if you are using gcc).
This behaviour is specific to C. C++, for example, does not allow that, and requires an explicit cast (C-style cast or a const_cast) to strip const qualifier, as you would reasonably expect.
Answer to the extended question
You are assigning a string literal into a non-const char, which, unfortunately, is legal in C and even C++! It is implicitly converted to char*, even though writing through this pointer will now result in undefined behaviour. It is a deprecated feature, and only C++0x so far does not allow this to happen.
With that said, In order to stop changing the pointer itself, you have to declare it as const pointer to char (char *const). Or, if you want to make it that both the contents pointed by it and the pointer itself don't change, use a const pointer to const char (const char * const).
Examples:
void foo (
char *a,
const char *b,
char *const c,
const char *const d)
{
char buf[10];
a = buf; /* OK, changing the pointer */
*a = 'a'; /* OK, changing contents pointed by pointer */
b = buf; /* OK, changing the pointer */
*b = 'b'; /* error, changing contents pointed by pointer */
c = buf; /* error, changing pointer */
*c = 'c'; /* OK, changing contents pointed by pointer */
d = buf; /* error, changing pointer */
*d = 'd'; /* error, changing contents pointed by pointer */
}
For all error lines GCC gives me "error: assignment of read-only location".
"const" is really a compile-time thing, so don't expect a segfault unless the pointer points to some invalid memory. When using const pointers in a way that could potentially alter whatever they point to (in this case passing it to strcpy which accepts non-const), will generate a warning.
1- What does const char *str in prototype actually means?
Does this mean that function cannot change the contents of str?
Yes! This means we cannot change the contents of something(either a char or an array of chars) pointed to by str.
If that is so then how come the above program changes the value?
Thats because strcpy()'s prototype is char * strcpy ( char * destination, const char * source );
In your code there is an implicit conversion from const char* to char* type because strcpy() requires its first argument to be of the type char*.
Technically speaking your code is incorrect rather dangerous. If you try the same code in C++ you'll surely get an error. C++ doesn't allow such implicit conversions but C does.
IIRC the const means that the value of the parameter may not be changed. I your case, the value is the address the pointer points to. strcpy doesn't change the address the pointer points to, but the memory the pointer points to.
Using const here makes sure that the memory reference (address) isn't changed. The memory referenced may be changed, however. This is what's happening here. Assigning a new address to the pointer would result in an error.
SIDE NOTE
I'd consider your foo method insecure. You'd better pass the maximum length of str as well and perform a length check, otherwise you'll be open for buffer overflows.
EDIT
I took the following from this site:
The const char *Str tells the compiler
that the DATA the pointer points too
is const. This means, Str can be
changed within Func, but *Str cannot.
As a copy of the pointer is passed to
Func, any changes made to Str are not
seen by main....
const char* is the same as char const* and not char* const. So this means a pointer to something you can't change.
Elaborating after your edit. The first form inhibits the data to be changed (unless you cast implicitly or explicitly) the second inhibits the pointer itself to be changed.
What you do in your edited version is to change the pointer. This is legal here. If you'd inhibit both you'd have to write char const* const.

Resources