After running the following C program with Valgrind, it says the packets.payload variable is uninitialised. But I cannot figure out why since I've already put "1234567890" in packets.payload
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct packet {
int payload_length;
char payload[10];
} packet_t;
int main () {
packet_t packet;
strncpy(packet.payload, "1234567890", 10);
puts(packet.payload);
}
A pointer to a string (a sequence of characters terminated by null-character) must be passed to puts().
Your packet.payload doesn't contain terminating null-character, so you cannot use it for puts().
You can use printf() with specifying length to print to print that:
printf("%.*s\n", 10, packet.payload);
packet_t packet ={0, "0000000"} is initialization. In the code, you are just assigning the value, not initialization. Initialization of a variable provides its initial value at the time of construction (definition).
Related
When I use the whole code in the main function it works perfectly but now I want to use the function for some "Strings" which I initialize in a 2D-Array.
The idea behind the function is to create a product of a struct globally initialized. The line with strcpy gives the error:
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
I am using Xcode 11.3.1 on a Mac.
Can you guys help me with that?
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <time.h>
struct produkt neues_angebot(char *produktname);
struct produkt{
char name[5];
int produkt_zahl;
float produkt_preis;
};
struct produkt neues_angebot(char *produktname){
time_t t;
srand((unsigned) time(&t));
struct produkt Zwischenname = {
"xxx",(rand() % 49),((rand()% 600)/100)
};
strcpy(Zwischenname.name, produktname);
return Zwischenname;
}
int main(int argc, const char * argv[]) {
char teste[]="hello";
printf("%s\n",neues_angebot(teste).name);
}
Strings in C are null terminated. The string "hello" uses 6 bytes of storage: the 5 characters h e l l o plus the terminating null character.
Now strcpy does no length checking, so strcpy(Zwischenname.name, produktname) will attempt to copy all 6 of those bytes into the array Zwischenname.name, which only has space for 5 bytes. That overflows the array and is undefined behavior - the crash you observed is one of the many possible results.
The strcpy will copy the last character of teste, the null terminator '\0', to outside the bounds of the the destination buffer as it is one byte shorter than it needs to be, this will cause Zwischenname.name to not be null terminated.
The problem is printf will need the null-terminator to know where the string ends in order work correctly, passing a non null-terminated character array as an argument to printf("%s", argument); invokes undefined behavior.
Remember, in order for an array of characters to be treated as a propper string it needs to be null terminated, many library fuctions in C rely on this principle. Always make sure that it is.
I"m a begginer in C, usually I used C++. I try to work whith a struct with a char array in it, but when I used an other char *str it raises a segfault.
My code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct s_obj t_obj;
struct s_obj {
char *str;
};
int main() {
char *str; // if disable no segmentation fault
t_obj obj;
printf("%lu\n",strlen(obj.str));
return(0);
}
I tried to understand what you mean by "the argument of strlen must be a string" #anastaciu... so I tried to make a code to do that, but the result is the same: segfault when an other char *str is used.
I can't find a way to init my char *str in the struct.
typedef struct s_obj t_obj;
struct s_obj {
char *str;
};
int main() {
char *str; // if disable no segmentation fault fault
t_obj obj;
obj.str = strcpy(obj.str, "truc");
// printf("%lu\n",strlen(obj.str));
printf("%s\n",obj.str);
return(0);
}
The line
printf("%lu\n", strlen(obj.str));
Invokes undefined behavior, the argument of strlen must be a string, aka a null terminated char array, obj.str is not a string it is just an uninitialized pointer, you'll need to allocate memory for it or othewise make it point to a valid memory location.
For example:
t_obj obj;
obj.str = calloc(100, sizeof *obj.str); //99 character string, 0 initialized
//malloc does not "clear" the allocated memory
//if you use it you can't use strlen before strcpy
printf("%zu\n",strlen(obj.str)); //will print 0, the string is empty
obj.str = strcpy(obj.str, "truc");
printf("%zu\n",strlen(obj.str)); //will print 4, the length of the string
Live demo
Tha fact that the program does not behave as badly when you remove char *str; is a matter that's well within the scope of undefined behavior:
C is not C++ ;) Seems you've missed an important difference regarding the two.
C++ Example:
#include <string>
struct t_obj {
std::string str;
};
void foo(){
t_obj obj; // <-- In C++ this is enough to get a properly initialized instance.
}
In C++, this code will give you a properly initialized object with an (also initialized) string.
But in C (as in your sample):
typedef struct t_obj t_obj;
struct t_obj {
char *str;
};
void foo(){
t_obj obj; // <-- Nothing gets initialized here.
}
There is no initialization as in the C++ example above. obj will simply be a chunk of (not initialized) memory. You have to initialize it yourself.
There's also a Problem with your 2nd sample:
strcpy does not work that way. We need to pass an allocated chunk of memory to strcpy and it will copy data to that place we gave to it.
But as we pass a "not initialzed pointer", strcpy will try to write our data somewhere in memory.
I think question "whats the difference between C strings and C++ strings?" might be helpful. It explains some details about the difference of C and C++ strings.
In either case, you are using obj.str uninitialised.
The address it holds in indeterminate, and the content of the memory location it points to also indeterminate. So, it's not null-terminated, and using it with strlen() (i.e., with the functions which expects a string argument), will cause out of bound access, which is essentially invalid memory access, which in turn invokes undefined behaviour.
For reference, C11, chapter 7.24, String handling <string.h>
[...]Unless explicitly stated otherwise in the description of a particular function in this subclause, pointer arguments on such a call shall still have valid values,[...]
At least, initialize the pointers to a null-value.
now the code work fine like that:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct s_obj t_obj;
struct s_obj {
char *str;
};
int main() {
char *str;
t_obj obj;
if (!(obj.str = (char*)malloc(sizeof(char))))
return (0);
obj.str = strcpy(obj.str, "truc");
printf("%s\n",obj.str);
free(obj.str);
return(0);
}
This question already has answers here:
Crash or "segmentation fault" when data is copied/scanned/read to an uninitialized pointer
(5 answers)
Closed 6 years ago.
this is my code giving segmentation fault
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(void) {
char *get;
scanf("%s", get);
int k = strcmp("sachin", get);
printf("%d", k);
}
thanks for any help;
char *get;
The above statement defines get to be a pointer to a character. It can store the address of an object of type char, not a character itself. The problem is with both scanf and strcmp call. You need to define an array of characters to store the input string.
#include <stdio.h>
#include <string.h>
int main(void) {
// assuming max string length 40
// +1 for the terminating null byte added by scanf
char get[40+1];
// "%40s" means write at most 40 characters
// into the buffer get and then add the null byte
// at the end. This is to guard against buffer overrun by
// scanf in case the input string is too large for get to store
scanf("%40s", get);
int k = strcmp("sachin", get);
printf("%d", k);
return 0;
}
You need to allocate memory for the pointer get.
Or use a char array:
char get[MAX_SIZE];
scanf("%s",get);
When you declare a pointer, it is not pointing to any memory address. You have to explicitly allocate memory for that pointer by malloc (c-style) or new (c++ style).
You will also need to manage the clean operation yourself by free / delete respectively.
of sure you get a segment fault.
you told your computer to write user input to uninitialized pointer.
char *get; // just a pointer that may wildly points anywhere
scanf("%s",get);
define get to be some char array
char get[SOME_LARGE_CONSTANTS_THAT_CLEARLY_IS_LARGER_THAN_YOUR_USER_INPUT];
The two following codes are similar but the first has a structure, the second not.
Why this code works (with no warnings)?
#include <stdio.h>
#include <string.h>
struct prova
{
char *stringa;
};
int main()
{
struct prova p;
strcpy (p.stringa, "example\0");
printf("%s\n", p.stringa);
return 0;
}
But the following code doesn't work?
Segmentation fault (core dumped)
With this warning:
code.c: In function ‘main’:
code.c:8:9: warning: ‘stringa’ is used uninitialized in this function [-Wuninitialized]
strcpy (stringa, "example\0");
#include <stdio.h>
#include <string.h>
int main()
{
char *stringa;
strcpy (stringa, "example\0");
printf("%s\n", stringa);
return 0;
}
Thank you!
Neither is correct because you copy to an address specified by an uninitialized variable. Therefore both programs invoke undefined behaviour.
The fact that one of the programs works is down to pure chance. One possible form of undefined behaviour is that your program runs correctly.
You need to initialize the pointer to refer to a sufficiently sized block of memory. For instance:
char *stringa = malloc(8);
Note that you do not need to add a null terminator to a string literal. That is implicit. So, given this memory allocation you can then write:
strcpy(stringa, "example");
You need to give the string some memory for it copy the characters to.
Use malloc
besides the first example does not compile.
When you write
struct prova
{
char *stringa;
};
int main()
{
struct prova p;
strcpy (p.stringa, "example\0");
notice that p.stringa points to nowhere in particular but you copy to it.
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