C - Static char array vs dynamic char array - c

This code compiles with a warning but prints the input string:
char staticArray[100];
scanf("%s",&staticArray);
printf("%s\n", staticArray);
Warning: format specifies type 'char *' but the argument has type 'char (*)[100]' [-Wformat]
This code also compiles with a warning but throws segmentation fault:
char* dynamicArray;
dynamicArray = (char*) malloc(sizeof(char)*100);
scanf("%s", &dynamicArray);
printf("%s\n", dynamicArray);
Warning: format specifies type 'char *' but the argument has type 'char **' [-Wformat]
I know both are wrong but, why does the first one prints the string value?

why does the first one prints the string value whereas second give segfault?
What's happening in Case I:
The type of staticArray is char [100] i.e. array of 100 char.
The type of &staticArray is char (*)[100].
The %s format specifier in scanf() expect the argument as a pointer to initial element of char array i.e. of type char *.
You are passing char (*)[100] type to scanf(), hence compiler is giving warning on this statement.
The &staticArray give you pointer to the array of type char (*)[100] which is numerically same as the base address of array.
Consider this example:
#include <stdio.h>
int main(void)
{
char staticArray[100];
printf ("staticArray: %p\n", (void*)staticArray);
printf ("&staticArray : %p\n", (void*)&staticArray);
return 0;
}
Output:
## ./a.out
staticArray: 0x7ffee4044a70
&staticArray : 0x7ffee4044a70
staticArray and &staticArray both yield a pointer to the same address1) but their type is different.
That's why when you pass &staticArray to scanf(), getting warning during compilation due to type mismatch but when scanf() called, it treat that pointer as char * and read input and store the result to given location. When printing it later, it prints the string value.
What's happening in Case II:
The type of dynamicArray is char *.
The type of &dynamicArray is char **.
So, you are passing char ** type to scanf() which expects char * when %s format specifier is used. Hence compiler is giving warning on this statement.
The pointer &dynamicArray is different from dynamicArray.
Consider this example:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char* dynamicArray;
dynamicArray = malloc(sizeof(char)*100);
if (dynamicArray == NULL) {
exit(EXIT_FAILURE);
}
printf ("dynamicArray: %p\n", (void*)dynamicArray);
printf ("&dynamicArray : %p\n", (void*)&dynamicArray);
free(dynamicArray);
return 0;
}
Output:
## ./a.out
dynamicArray: 0x7fd615401690
&dynamicArray : 0x7ffee7ab7ad0
dynamicArray and &dynamicArray both yield different pointer.
When you pass &dynamicArray to scanf() (which read input and store the result to given location), it lead to undefined behavior2) because your program end up accessing invalid memory.
When you pass &dynamicArray to printf() with format specifier %s, printf(), it access that address to write the character string and end up accessing invalid memory, lead to undefined behavior2). Hence, you are getting segfault.
1) An array is automatically converted to a pointer to its first element but there are few exceptions to this rule (C11 Standards#6.3.2.1p3):
The array is the operand of sizeof operator.
The array is the operand of _Alignof operator.
The array is the operand of &.
The array is a string literal used to initialize an array.
2) An undefined behavior includes it may execute incorrectly (either crashing or silently generating incorrect results), or it may fortuitously do exactly what the programmer intended.

Removing the & operator in both examples will solve the warnings. I'm not sure what your intended behavior is, but they seem to work correctly upon moving the & operator. This is because arrays are inherently pointers to the first element of the array so adding & is not what you want.
Working examples(exactly the same expect for &):
char staticArray[100];
scanf("%s",staticArray);
printf("%s\n", staticArray);
and
char* dynamicArray;
dynamicArray = (char*) malloc(sizeof(char)*100);
scanf("%s", dynamicArray);
printf("%s\n", dynamicArray);

Related

Dereferencing char pointer returns int ? why? [duplicate]

This question already has answers here:
Char pointers and the printf function
(6 answers)
Closed 1 year ago.
For example, the following code returns an error and a warning when compiled and an int when changed to %d
Warning:
format %s expects argument of type char *, but argument 2 has type int
void stringd() {
char *s = "Hello";
printf("derefernced s is %s", *s);
}
*s is an expression of type char since it's the dereference operator applied to a pointer-to-char1. As a result, it gets promoted to an int when passed to printf; in order to print a null-terminated string, you need to pass the pointer to the first character (i.e. just s).
1 even though s is not a const pointer, you should not try to modify the characters it points to as they may be placed in read-only memory where string literals are stored on some architectures/environments; see this discussion for more details.
The variable s is a pointer to the first out of a series of characters which are consecutive in memory (colloquially referred to as a "string", though it's not quite the same). It's a pointer to a character, thus char *.
Dereferencing s (by doing *s) gives you the first of those characters, h, whose type is now just char. One layer of indirection was stripped away.
Thus, the issue is that you're trying to pass a character (char), where a string (char *) was expected. char * was expected because you used the %s type character in your format string to printf. Instead, you should use %c, which expects single, simple char.
The mistake here is actually quite grave. If you were allowed to pass this 'h' where a char * was expected, you would end up with the ASCII code of 'h' (0x68) being passed where a pointer was expected. printf would be none-the-wiser, and would try to dereference that value, treating 0x68 like a pointer to the beginning of a string. Of course, that's probably not a valid memory location in your program, so that should seg-fault pretty reliability, if it were allowed to happen.

why can't we use indirection operator with array name?

In the below code , why can't I dereference the array name ,since when an array is passed as an argument to a function , it becomes pointer to first element of the array , so why can't we dereference it then ?
#include <stdio.h>
int main(void) {
char s[] = "radha";
int a[2] = {0,1};
printf("%s ", *s);
printf("%d", *a);
return 0;
}
​
I am getting segmentation fault for the above code , what's the reason here , when I use a[0] ,it is internally converted as *(a+0) , so what's the issue in simply doing *a or *S ,please clarify .
printf("%s ",*s); expects second argument to be a pointer to string while you are passing char 'r' (dereferencing s gives you first array item as expected).
I have two suggestions of your,
Read the documentation.
The "%s" specifier expects a pointer of char, you are passing a char which is then considered an integer and dereference as if it were a pointer causing UNDEFINED BEHAVIOR.
If you read the documentation, and understand that char[] is converted to char * also that dereferencing a char * poitner will give you a char, then you would understand why this is wrong.
Enable compiler warnings. If you do so, then a warning telling you that you are passing the wrong type would save you a lot of time and let you learn more about how to invoke a given function.
If you ignored the warning, it's even worse. You should never ignore a warning unless you know beforehand that the compiler will complain about something. If the warning was not expected, then it's very likely an error instead.

Confused about pointers and structures

I'm trying to compare a string stored in a structure. I'm using scanf to input a string and I need to search for the string in the structure. Here is the code I have:
int printing_airports(int all_routes_size,int all_airports_size){
int i,position;
char airport;
printf("Enter airport code: ");
scanf("%s", airport);
for(i=0;i<all_airports_size;i++){
if(strcmp(airport,all_airports_divid[i].code) == 0){
position = i;
}
}
printf("%s",all_airports_divid[position].code);
}
This is how I declared my structures
struct all_routes{
int id;
char departure_code[4];
char arrival_code[4];
};
struct all_routes all_routes_divid[500];
This is the error I'm getting when I tried to compile
y:~/enee150/project2: compile
functions.c: In function 'printing_airports':
functions.c:370:15: error: invalid type argument of unary '*' (have 'int')
functions.c:373:5: warning: passing argument 1 of 'strcmp' makes pointer from integer without a cast [enabled by default]
/usr/include/iso/string_iso.h:64:12: note: expected 'const char *' but argument is of type 'char'
What am I doing wrong? Please help me.
You declare airport as a char
char airport;
but use it as a string. Declare it char airport[100]; or so.
printf("Enter airport code: ");
scanf("%s", airport);
scanf requires a pointer to the variable the result shall be stored in as argument. When declared as char, airport is passed as an int to scanf, that is why the first message mentions int. The argument is dereferenced (unary *) to find the location where to store the scan result.
for(i=0;i<all_airports_size;i++){
if(strcmp(airport,all_airports_divid[i].code) == 0){
strcmp requires a pointer (to a 0-terminated string) as argument. If passed an integral type like char, without explicit cast, the compiler warns about that (because 99.99+% of the time it's wrong to do that).
Instead of passing a char to scanf, you need to pass it a char *; that is, a pointer to a place in memory where it can write the string that it finds.
To do this, instead of declaring airport as a single char, you need to declare it as an array; say, char[20]. This would not be suitable for a real application, because if the string was greater than 20 characters it would introduce a buffer overflow vulnerability, but it should be good enough for your purposes.
char airport;
Are you only expecting one char?
I think what you want is a char* hence that last line in the error.
Using char[42] would also work.
Or you could actually allocate some characters, but that doesn't seem to fit with this assignment.
char airport; // This must be a char* or char[] to hold the code
printf("Enter airport code: ");
scanf("%s", airport); // scanf expects address of the string, while airport is a char
for(i=0;i
Moreover, there is no field by the name of code in the declared struct

segmentation fault in C assign string to char

#include <stdio.h>
#include <stdlib.h>
int main()
{
char a="9jhjhi";
printf("%s",a);
}
Why does this throw a segmentation fault? What happens behind the screens?
You need to use char *a = "...".
printf when passed %s will run through a string looking for a 0/NULL byte. In your case you are not assigning a string literal to a, and in fact your compiler should have thrown a warning that you were trying to initialize a char from a pointer.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *a="9jhjhi";
printf("%s",a);
}
Your error is that
char a="9jhjhi";
should be
char *a="9jhjhi";
What happens is undefined behavior - so anything could happen.
Your assigning a string literal to a char, so your a will contain a pointer(to the beginning of that string) converted to a char - whatever that'll be.
%s conversion in printf assumes you pass it a string, which must be a char* pointing to a sequence of chars ending with a 0 terminator. You passed it a char, which certainly does not meet those requirements, so it's quite undefined what'll happen - a crash could be common.
You should also return something from the main() method - it's declared to return an int after all.
a is initialized to a (cast to integer and truncated because char is 3 or 7 bytes too small) pointer that points to a char array (propably somewhere in ROM). What follows is undefined, but it's propably like this: When you pass it to printf with a %s in the format string, it takes the value of a (something in 0-255) and 3 (or 7) unrelated bytes from the stack, gets some bogus address and wreaks havok by accessing someone else's memory.
Use char *a = ....
C does not have strings as in String b = new String();
C has arrays of type char.
So char a="123123" should be a character array.
You aren't using anything from stdlib.h in that code either so there is no reason to #include it.
Edit: yeah, what nos said too. An array name is a pointer.
You mean
char *a = "9jhjhi";
If this compiles without warnings, your compiler settings are messed up. The warnings from gcc show plainly what's happening:
test.c: In function ‘main’:
test.c:5: warning: initialization makes integer from pointer without a cast
test.c:6: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘int’
The string literal is interpreted as a pointer, which is converted (and truncated) to a char.
Then the char is sent into printf as a number, but interpreted as a string. Since it's not null-terminated in any way, printf probably overruns memory when racing through that "string".
When you declare char a without a pointer symbol, you are only allocating enough space on the stack for a single character.
Strings in C are represented by a char array, or a pointer to a char array, terminated by the null character '\0'. But if you use a literal string, the compiler takes care of all of that for you.
Here's how you can get your code to work, then:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *a = "9jhjhi";
printf("%s",a);
}
First of all, you're trying to save an entire string into a single char variable. Use char array (char[size]) instead. You may also want to terminate the string with "\0".
You could remove this error in two ways.
1.char * p="karthik A"
2.char [ ]p="karthik A"

Question about char pointers

I am confused with this program.
#include <stdio.h>
int main(void)
{
char* ptr="MET ADSD";
*ptr++;
printf("%c\n", ptr);
ptr++;
printf("%c\n", ptr);
}
Here's the output.
ET ADSD
T ADSD
My question is how does the pointer display the rest of the characters?
You are passing a wrong combination of parameters to printf: the %c format specification requires a char parameter, not a char*. So the result is undefined - in your case printf seems to print the whole char array, but this is just by pure chance. Use either
printf("%c\n", *ptr);
or
printf("%s\n", ptr);
You are actually trying to print as a char %c a pointer value char*. This is false. But then, I really don't understand why it prints all the chars. Are you sure you didn't use %s instead of %c?
The * operator as lower precedence over the ++ operator. Thus in your example the both lines
*ptr++;
ptr++;
have the same effect.
And you are using the wrong types in your printf statement.
Change
printf("%c\n", ptr);
to
printf("%s\n", ptr);
or
printf("%c\n", *ptr);
depending on what you want to output.
Btw, turning on compiler warnings helps in that case. E.g. the GCC prints:
d.c: In function ‘main’:
d.c:7: warning: value computed is not used
d.c:8: warning: format ‘%c’ expects type ‘int’, but argument 2 has type ‘char *’
d.c:11: warning: format ‘%c’ expects type ‘int’, but argument 2 has type ‘char *’
d.c:12: warning: control reaches end of non-void function
In C a string is a array of chars, and an array is simply a pointer to the first location of memory of the array.
So defining
char* ptr="MET ADSD";
you are declaring and initializing an array of chars, a string, by using a pointer to char,
The next trick comes if you consider this two factors:
pointers arithmetic in that using the operator ++ on a pointer increments its value, the memory address it is pointing to
char size which is almost everywhere 1 byte
So you are scaling the array along of two positions, and you print that by using %s and passing the pointer to it
EDIT I guess you put %c mistakenly in the example
If you are expecting 'E' as first and 'T' as second output. Give it like
#include <stdio.h>
int main(void)
{
char* ptr="MET ADSD";
*ptr++;
printf("%c\n", *ptr);
ptr++;
printf("%c\n", *ptr);
}
printf( ..., ptr) is passing the pointer, not the char it points to.
The correct version of the program would be:
#include <stdio.h>
int main(int argc, char* argv[])
{
const char* ptr = "MET ADSD";
ptr++;
printf("%c\n", *ptr);
ptr++;
printf("%c\n", *ptr);
return 0;
}
which will print
E
T
The output you are seeing makes no sense unless you are using %s. - %c is going to convert the value of ptr into an integer, truncate the int to 8bits (the width of a char), and print that character to the output. Not a string of characters.

Resources