De-referencing char pointer run-time error - c

Why does the below code cause a run-time crash?
The code itself is not very useful, but , by creating a pointer to a char pointer and pointing to string literals in main, passing this pointer to my function and trying to read the strings causes problems. Why is that exactly?
By creating an array of strings instead in main however (commented out) , there are no problems in passing and reading the strings. Thanks in advance for your knowledge.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* GetString(char** strs, int strsSize);
char* GetString(char** strs, int strsSize)
{
return *strs;
}
int main()
{
char** stringArr = {"ab", "abc", "abcd"};
//char* stringArr [] = {"ab", "abc", "abcd"};
char* resultStr;
resultStr = GetString(stringArr, 3);
printf("%s\n", resultStr);
return 0;
}

The initializer for stringArr is not valid. You have a pointer to a pointer, not an array. A pointer cannot be initialized with the {} syntax.
When compiling with -Wall -Wextra, the following warnings are produced:
/tmp/x1.c: In function ‘main’:
/tmp/x1.c:15: warning: initialization from incompatible pointer type
/tmp/x1.c:15: warning: excess elements in scalar initializer
/tmp/x1.c:15: warning: (near initialization for ‘stringArr’)
/tmp/x1.c:15: warning: excess elements in scalar initializer
/tmp/x1.c:15: warning: (near initialization for ‘stringArr’)
The commented out declaration you have is the correct one.
Both declarations are valid to be passed to GetString because an array decays into a pointer to the first element when passed to a function. However, a pointer and an array are not the same thing.

Related

Why below printf causes segmentation fault?

Why below printf causes segmentation fault?
#include <stdio.h>
int main()
{
int *intp = {1,2,3,4,5};
printf("%d", *intp);
return 0;
}
Check it on onlinegdb.com
In your case, you are trying to initialize a pointer with a brace enclosed initializer list of ints, which is invalid.
int *intp = {1,2,3,4,5};
If you try to compile your code with proper warnings enabled, you'll see the compiler warning messages like
source_file.c: In function ‘main’:
source_file.c:9:18: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
int *intp = {1,2,3,4,5};
^
source_file.c:9:18: note: (near initialization for ‘intp’)
source_file.c:9:20: warning: excess elements in scalar initializer
int *intp = {1,2,3,4,5};
^
source_file.c:9:20: note: (near initialization for ‘intp’)
source_file.c:9:22: warning: excess elements in scalar initializer
int *intp = {1,2,3,4,5};
^
source_file.c:9:22: note: (near initialization for ‘intp’)
source_file.c:9:24: warning: excess elements in scalar initializer
int *intp = {1,2,3,4,5};
^
source_file.c:9:24: note: (near initialization for ‘intp’)
source_file.c:9:26: warning: excess elements in scalar initializer
int *intp = {1,2,3,4,5};
This statement in your code is a constraint violation and does not mean anything meaningful. For a scalar, the initializer should be a single expression: as stated in C11, chapter §6.7.9
The initializer for a scalar shall be a single expression, optionally enclosed in braces. [...]
Thus, a brace enclosed list is not a suitable initializer for a scalar.
You can change the pointer to an array and have that initialized with the initializer statement, but not a pointer.
Then, later, when you try to dereference, you're essentially making an attempt to dereference an invalid memory, which invokes undefined behaviour.
Changing your code to something like
int intp[] = {1,2,3,4,5};
would do the job.

Why do I get: "error: assignment to expression with array type"

#include <stdio.h>
int main(void) {
int arr[10];
arr = "Hello";
printf("%s",arr);
return 0;
}
The above code shows compiler error:
t.c: In function ‘main’:
t.c:5:9: error: assignment to expression with array type
arr = "Hello";
^
t.c:6:12: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int *’ [-Wformat=]
printf("%s",arr);
^
Whereas the below code works fine.
#include <stdio.h>
int main(void) {
char arr[10] = "Hello";
printf("%s",arr);
return 0;
}
Both look identical to me. What am I missing here?
They are not identical.
First of all, it makes zero sense to initialize an int array with a string literal, and in worst case, it may invoke undefined behavior, as pointer to integer conversion and the validity of the converted result thereafter is highly platform-specific behaviour. In this regard, both the snippets are invalid.
Then, correcting the data type, considering the char array is used,
In the first case,
arr = "Hello";
is an assignment, which is not allowed with an array type as LHS of assignment.
OTOH,
char arr[10] = "Hello";
is an initialization statement, which is perfectly valid statement.
Don't know how your second code is working (its not working in my case PLEASE TELL ME WHAT CAN BE THE REASON) it is saying: array of inappropriate type (int) initialized with string constant
Since you can't just assign a whole string to a integer variable.
but you can assign a single character to a int variable like:
int a[5]={'a','b','c','d','d'}

Why am I getting warning: (near initialization for ‘ptr’) and segmentation fault at runtime when accsessing value at pointer?

This is the following code:
Why it is giving segmentation fault when I try to access first value of array?
What are all this warnings?
#include<stdio.h>
int main(void)
{
int *ptr = {1,2,3,4,5};//Is it not similar to char *ptr="Stackoverflow"?
printf("%d\n",*ptr);// why Segmentation fault(core dumped) instead of 1
return 0;
}
...
output:
warning: initialization makes pointer from integer without a cast [enabled by default]
int *ptr = {1,2,3,4,5};
^
warning: (near initialization for ‘ptr’) [enabled by default]
warning: excess elements in scalar initializer [enabled by default]
warning: (near initialization for ‘ptr’) [enabled by default]
warning: excess elements in scalar initializer [enabled by default]
warning: (near initialization for ‘ptr’) [enabled by default]
warning: excess elements in scalar initializer [enabled by default]
warning: (near initialization for ‘ptr’) [enabled by default]
warning: excess elements in scalar initializer [enabled by default]
warning: (near initialization for ‘ptr’) [enabled by default]
//Is it not similar to char *ptr="Stackoverflow"?
TL;DR No, it is not.
The used initializer, {1,2,3,4,5} is called a brace-enclosed initalizer which is supposed to initialize the values of the type of the elements. This is used for aggregate or union type type, like mentioned as in C11, chapter §6.7.9, Initialization
the initializer for an object that has aggregate or union type shall be a brace enclosed
list of initializers for the elements or named members.
Here, the initializer list contains all int values, and you're trying to initialize a pointer thought it. This is wrong.
Also, regarding the scalar type, quoting C11, chapter §6.2.5
Arithmetic types and pointer types are collectively called scalar types.[...]
and the aggregate types
[...]Array and
structure types are collectively called aggregate types.
There are many issues here, like
You're using int value to initialize an int *.
You're ending up supplying a brace enclosed list containing more than one initializer element for a scalar object.
So, later in your code,
printf("%d\n",*ptr);
is essentially an invalid memory access, which invokes undefined behavior. The segmentation fault is one of the many side-effects.
Coming to the point of the comment,
char *ptr="Stackoverflow"?
In case of char *ptr="Stackoverflow";, here, "Stackoverflow" is called a string literal and ptr is initalized with the base address of the string literal.
Solution:
You need to have an array of ints which you can initialize using the brace-enclosed initializer. Something along the line of
int ptr[] = {1,2,3,4,5};
will be valid. Then you can use it like
for(int i = 0; i < 5; i++)
printf("%d\t", *(ptr+i));
Your original code is invalid. It contains at least two constraint violations: it provides initializers for objects that don't exist, and it tries to use an initializer 1 (of type int) for an int* object. A compiler could (and IMHO should) simply reject it. gcc is being overly permissive by compiling your code after merely warning about the errors. The resulting code has undefined behavior.
const char *cptr = "Hello";
The above is valid. "Hello" is an expression of array type (specifically of type char[6]). In most contexts, including this one, such an expression is implicitly converted to a pointer to the array's 0th element. Note that I've added const so the compiler will at least warn if I attempt to modify the data that cptr points to.
int *iptr = { 1, 2, 3, 4, 5 }; // invalid
This is invalid. You might expect that it's handled similarly to cptr. The problem is that { 1, 2, 3, 4, 5 } is not an expression; it's valid only in an initializer. It could be a valid initializer for an array object, but since it's not an expression, the array-to-pointer conversion rule doesn't apply.
Assuming your compiler supports C99 or later (specifically the compound literal feature), you can write:
int *iptr = (int[]){ 1, 2, 3, 4, 5 };
(This is not a cast; the syntax is similar, but the { ... } is not an expression.)
The compound literal is an expression of array type, specifically int[5], and the array-to-pointer conversion applies.
One caveat: A string literal creates an array object, and that object has static storage duration, meaning that it exists throughout the execution of the program. A compound literal creates an object with static storage duration only if it appears outside any function; inside a function, it creates an object with automatic storage duration, meaning that it ceases to exist when you reach the end of the current block. In this case, it's defined inside the main function, so it's not likely to be an issue. But it's something to watch out for. For example, this is safe:
const char *new_string(void) {
const char *result = "hello";
return result;
}
but this is not:
int *new_array(void) {
int *result = (int[]){ 1, 2, 3, 4, 5 };
return result; /* BAD! */
}
because the array ceases to exist when you leave the function. To avoid that, you can create the array object explicitly to make it static:
int *new_array(void) {
static const int arr[] = { 1, 2, 3, 4, 5 };
int *result = arr; /* or &arr[0] */
return result; /* or "return arr;" */
}
basically that line is invalid, the c compiler has tried to make sense of it but really cannot. You need the syntax here
How to initialize all members of an array to the same value?
Summary
int myArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
try:
#include<stdio.h>
int main(void)
{
int ptr[] = {1,2,3,4,5};//Is it not similar to char *ptr="Stackoverflow"?
printf("%d\n",*ptr);// why Segmentation fault(core dumped) instead of 1
return 0;
}
In the original code:
int *ptr = {1,2,3,4,5};
{1,2,3,4,5} won't initialize an integer array. String initialization is a special case which is not applicable over other types.
So this code will initialize an integer pointer which will point to memoery address 0x00000001 (first one in the initializer block)
This address is out of program scope and thus segmentation error came into picture.
Pointer is a scalar data type and standard says that (C11-6.7.9):
The initializer for a scalar shall be a single expression, optionally enclosed in braces.
You can't initialize a scalar data type with brace enclosed initializer having more than one expressions.
In case of
char *ptr="Stackoverflow";
ptr is pointing to the object with type array of char (look at standard C11:§6.7.9/11). It just initializes ptr to the start of the address of string literal.
You are trying to store values in an unitialised pointer. The value of the pointer must be attached to a memory location prior you can access it.
Just do some malloc before:
int $ptr;
ptr = malloc( 5* sizeof(int)); // since you have 5 values and then you can initialize your data
for (i=0;i<5;i++) {
(*ptr+i) = (i+1);
}

assignment makes pointer from integer without a cast [enabled by default] when assigning char pointer to character array

I'm trying to return a pointer to a character array. The function is located in a different file. I compile the files together and it prints out "hello" just fine, but still produces a warning
warning: assignment makes pointer from integer without a cast [enabled by default]
I tried casting the returned value of function() to (char *), but ended up with a different warning:
warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]" instead.
What am I doing wrong?
File 1
#include <stdio.h>
int main()
{
printf("%s\n", function());
return 0;
}
File 2
#include <stdio.h>
char *message = "hello";
char *function()
{
return(message);
}
The problem here is a missing prototype. For historical reasons C lets you use functions without declaring them. However, all such functions are considered returning int, and all their parameters are considered int as well.
Since your function returns char*, you need to add a prototype for it (it's a good idea to have prototypes for all your functions, including ones that indeed return an int):
#include <stdio.h>
char *function(); // <<== Add this line
int main()
{
printf("%s\n", function());
return 0;
}

pointer to a char

I have query on how to assign a pointer to a character
Sample program:
#include <stdio.h>
void main()
{
const char str1[]="MANCHESTER";
char *q;
q=str1;
*q='A';
printf("%s\n",q);
}
In the the above program, I am assigning a character pointer to string "str1",
When I compile the program with gcc, I get the below warning:
ptr3.c: In function ‘main’:
ptr3.c:7:3: warning: assignment discards qualifiers from pointer target type
I am not able to understand what the warning means.
warnings i get:
2: warning: return type of 'main' is not 'int'
: In function 'main':
7: warning: implicit declaration of function 'printf'
7: warning: incompatible implicit declaration of built-in function 'printf'
adding include stdio.h and return type int, fixes those.
#include <stdio.h>
int main()
{
char str1[]="MANCHESTER";
char *q;
q=str1;
*q='A';
printf("%s\n",q);
return 0;
}
edit:
i guess you should not declare the char array as const, if you plan on modifying it, directly or indirectly through another pointer

Resources