C sprintf overwrite? - c

Can someone explain me why this doesn't work? It appears that the program stops at sprintf(t->tuple[0], "abc"); and I don't know why. Really need help.
int testRemoveMeio(){
int result, i;
struct list_t *list = list_create();
char *tdata[3] = {" ", "2014", "Fixe!"};
struct tuple_t *t = tuple_create2(3, tdata);
struct tuple_t *tdups[4];
struct entry_t *entries[4];
sprintf(t->tuple[0], "abc");
tdups[0] = tuple_dup(t);
entries[0] = entry_create(tdups[0]);
list_add(list, entries[0]);
//extra code similar to above
return 0;
}
Edit:
struct tuple_t {
int tuple_dimension;
char **tuple;
};
struct tuple_t *tuple_create2(int tuple_dim, char **tuple){
struct tuple_t *t = (struct tuple_t *) malloc(sizeof(struct tuple_t));
if(t == NULL)
return NULL;
t->tuple_dimension = tuple_dim;
t->tuple = tuple;
return t;
}
Edited to add another example from the comments:
#include <stdio.h>
#include <string.h>
int main(void)
{
char * s = "ABC";
printf("%s\n",s);
sprintf(s,"DEF");
printf("%s\n",s);
return 0;
}

I pasted the code from your comment into the question. Both that and your original code are failing for the same reason, I think: you're modifying string literals.
It's sad but true that in C, string literals like "hello world" are illegal to modify, yet are assignable to char* without const and without a cast. This makes it easy to screw up, because modifying such a string is undefined behavior, because it may reside in read-only memory in your program.
To fix it, try this:
char tdata[3][6] = {" ", "2014", "Fixe!"};
Or in your second example:
char s[] = "ABC";
This way you are allocating an actual character array with writable storage. But please, always use snprintf() and never sprintf() because the latter is prone to buffer overruns which can crash your program or worse.

You second example is wrong. You should use snprintf(3) (there is no reason to use sprintf in 2014; it is old and dangerous, since it may give a buffer overflow) on some array of char like this:
#include <stdio.h>
int main(void) {
char buf[64];
snprintf(buf, sizeof(buf), "here %s", "ABC");
printf("%s\n",buf);
return 0;
}
You could have used some dynamically allocated memory zone (but then, you should know its size), e.g.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
size_t siz=32;
char* ptr = malloc(siz);
if (!ptr) { perror("malloc"); exit(EXIT_FAILURE); };
snprintf(ptr, siz, "here %s and two is %d", "ABC", 2);
printf("%s\n", ptr);
free (ptr);
return 0;
}
You might use asprintf(3) if your system gives it (e.g. on Linux) like
#define _GNU_SOURCE
#include <stdio.h>
int main (void) {
char* ptrzone = NULL;
asprintf(&ptrzone, "and here %s and one is %d", "ABC", 1);
printf("%s\n", ptrzone);
free (ptrzone), ptrzone = NULL;
}
In serious programs, you often should use the result of snprintf.
Read the documentation of all the functions you are using, so also: perror(3), exit(3), malloc(3), free(3)
You absolutely should read more about C dynamic memory allocation
You should compile with all warnings and debug info (gcc -Wall -g) and learn to use the debugger (gdb) and the memory leak detector valgrind

Some important information is missing as the definition to struct tuple_t and the definition of function tuple_create2. If the error occurs on sprintf(t->tuple[0], "abc") then either t->tuple and/or t->tuple[0] is not correctly initialized/allocated. This former should be an array of at least 1 for the example (but more probably 3 if we look at tdata) strings and the latter to a string buffer (array of char). Check you or provide us the tuple_create2 function.
The way you use sprintf to copy a string is dangerous. On your example this works but if the string to copy contains the '%' character, bad things can happen (% is the character used to specify a format in printf/scanf family of functions. If you want to stay with sprinf use sprintf(t->tuple[0], "%s", "abc") but the simpler is strcpy(t->tuple[0], "abc")
Since you have now added the definition of tuple_create2, I try to answer.
In C, it is up to you to manage the memory. What do you expect from tuple_create2 ?. Your code allocates the space for the "header" (i.e. a struct tuple containing the dimension and an array of strings) and fills it with tuple. The result is a new object which points to the same memory for the data (i.e. the array of strings). This is OK except if you want to modify this array (which seems to be the case). There are 2 things: the array itself (each entry is a pointer to an array of chars - do you want to modify the pointers ?) and the strings (the content of the array of chars). There are several possibilities for this but this depends on you. For instance the function could allocate its own array of pointers and initialize with the existing data:
struct tuple_t *tuple_create2(int tuple_dim, char **tuple){
struct tuple_t *t = (struct tuple_t *) malloc(sizeof(struct tuple_t));
if(t == NULL)
return NULL;
t->tuple_dimension = tuple_dim;
t->tuple = (char **) malloc(sizeof(char *) * tuple_dim);
for(i = 0; i < tuple_dim; i++) // could be replaced by a memcpy
t->tuple[0] = tuple[0];
return t;
}
Then you have to be aware that we copied only pointers. So when you want to modify an element either you simply copy the pointer :
t->tuple[0] = "abc";
or you allocate a new string if you thing it can be modified and you don't want this. I give you an example with "abc" but this is not relevant because "abc" is a constant string which will not be modified. Anyway here is the code (note the use of stdrup which duplicates the string doing a malloc)
t->tuple[0] = strdup("abc");

Related

Do we need to initialize the pointers inside struct

We have pointers inside a struct, do we need to initialize the pointers inside the struct?
I have tried the code below, include this sentence below or not, the code all run well.
(Could some experts give help here? and I read some code, and found seems sometimes initialized, sometimes not, so confused and search/ask here.)
The answer in this link seems not mentioned initialize this pointer inside struct. initializing-a-member-of-a-structure-with-pointers-c
#include "stdio.h"
#include "stdlib.h"
struct part{
int num;
char *name;
};
int main()
{
struct part *p = (struct part*)malloc(sizeof(struct part));
//Include this or not, this code all run well
p->name = (char*)malloc(sizeof(char));
p->num = 1;
p->name = "ss";
printf("%d, %s\n", p->num, p->name);
return 0;
}
No, you should not do that, you are creating a memory leak, because you allocate memory and then forget the pointer value and don't free it.
To remove the memory leak:
p->name = malloc(1); //sizeof char is 1 by definition, and cast not needed
free(p->name);
p->name = "ss";
However, if you look at that, it should be clear that allocating 1 byte of memory, then immediately freeing it, is pointless.
Perhaps you want a copy of the string?
const char *initdata = "ss";
p->name = malloc(strlen(initdata)+1);
strcpy(p->name, initdata);
// Remember to free this at some point
Alternatively, you could use initialize with the string literal, but then you should have const char pointer because string literals are read-only:
struct part{
int num;
const char *name;
};

Copy a string to a *struct member

I've looked through topics of similar kind, but didn't find a solution for my problem. I've got a struct like
typedef struct {
int number;
char *string;
} mystruct;
//Then define a pointer to the struct:
mystruct *data;
// Allocate memory:
data = malloc(sizeof(mystruct));
//Assign some number, let's say 5:
(*data).number = 5;
//So far ok, works (checked: 5 can be retrieved from the struct somewhere else) but:
strcpy((*data).string = "Hello!");
//This line fails with segmentation fault.
I don't understand why? Can somebody please explain what I'm doing wrong?
As mentioned in the comments, the problem with your attempted strcpy call is that your destination (the string member of your data) isn't a pointer to valid memory. (I am assuming that your invalid syntax, strcpy((*data).string = "Hello!") is a typo, and that your real code has something like strcpy((*data).string, "Hello!") – otherwise, it won't even compile, so you won't get a segmentation fault.)
There are several approaches to fix this, depending on what you actually want to happen. First, as also mentioned in the comments, you can just copy the pointer to the destination, like this1:
data->string = "Hello!";
However, this may not be what you want, because, if the source is not actually a literal, but a modifiable string, then, after that assignment, any changes to the source will also apply to your copy.
If you want a copy of the source data, you will need to allocate sufficient space for it, then call strcpy; like this:
#include <stdlib.h> // For malloc
const char* src = "Hello!";
data->string = malloc(strlen(src) + 1); // Add 1 for the required nul-terminator
strcpy(data->string, src);
However, the strdup function2 does the job of the above malloc and strcpy calls in one fell swoop:
data->string = strdup("Hello!");
In each of the above two cases, be sure to call free(data->string) when you're finished.
1 Note that you can use the "member access through pointer" (->) operator, rather than dereferencing and then using the . operator: data->number = 5 is equivalent to your (*data).number = 5.
2 Some compilers/platforms may not support the strdup function, but it is part of the ISO C Standard from C23
As other users mentioned, you need to allocate space for the string.
I would use a flexible array member and have only one allocation for the struct and string.
typedef struct {
int number;
char string[];
} mystruct;
mystruct *create(const char *str)
{
mystruct *ms = NULL;
if(str)
{
ms = malloc(sizeof(*ms) + strlen(str) + 1);
if(ms)
{
strcpy(ms -> string, str);
ms -> number = 0;
}
}
return ms;
}
int main(void)
{
mystruct *ms = create("Hello");
if(ms)
{
printf("ms -> string = `%s`\n", ms -> string);
}
free(ms);
}
I am not sure to understand this line
strcpy((*data).string = "Hello!");
Do you mean
strcpy((*data).string, "Hello!");
I believe the issue is that your struct contain a pointer char * string that doesn't point to a valid allocated memory.
You can try multiple solutions
Have struct with predefined size
typedef struct {
int number;
char string[100];
} mystruct;
You can allocate memory for the string during the initialization
data = malloc(sizeof(mystruct));
data->string = malloc(sizeof(char) *100));

malloc, sizeof and strlen functions possible conflict?

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
typedef struct _person
{
char *fname;
char *lname;
bool isavailable;
}Person;
Person *getPersonInstance(void)
{
Person *newPerson = (Person*) malloc(sizeof(Person));
if(newPerson == NULL)
return NULL;
return newPerson;
}
void initializePerson(Person *person, char *fname, char *lname, bool isavailable)
{
person->fname = (char*) malloc(strlen(fname)+1);
/*problematic behaviour if i write: person->fname = (char*) malloc (sizeof(strlen(fname)+1)); */
person->lname = (char*) malloc(strlen(lname)+1);
/*problematic behaviour if i write: person->lname = (char*) malloc (sizeof(strlen(lname)+1)); */
strcpy(person->fname,fname);
strcpy(person->lname,lname);
person->isavailable = isavailable;
return;
}
// test code sample
int main(void)
{
Person *p1 =getPersonInstance();
if(p1 != NULL)
initializePerson(p1, "Bronze", "Medal", 1);
Person *p2 =getPersonInstance();
if(p2 != NULL)
initializePerson(p2, "Silver", "Medalion", 1);
Person *p3 =getPersonInstance();
if(p3 != NULL)
initializePerson(p3, "Golden", "Section", 1);
printf("item1=> %10s, %10s, %4u\n",p1->fname, p1->lname, p1->isavailable);
printf("item2=> %10s, %10s, %4u\n",p2->fname, p2->lname, p2->isavailable);
printf("item3=> %10s, %10s, %4u\n",p3->fname, p3->lname, p3->isavailable);
return 0;
}
Inside initializePerson() if i use:
person->fname = (char*) malloc (sizeof(strlen(fname)+1));
person->lname = (char*) malloc (sizeof(strlen(lname)+1));
When these two codelines are enabled instead of the ones i am using in the source code above, i might get a run time error when i test the code using CodeBlocks IDE. Very likely the console freezes up and stops working. If i test the code using ubuntu terminal it works any day without a problem regardless of the size of the input data.
Question: (Now, assume that we are using the 2 pieces of code from the previous paragraph) i know that sizeof counts bytes, and strlen counts the number of characters until it finds null... BUT sizeof and strlen when used together inside malloc() do they cause a conflict in the background? What seems to be the problem? why the code has such an erratic,unreliable behavior? why?
sizeof(strlen(fname)+1) doesn't make any sense. It gives the size of the result type of strlen, which is an integer of 4 bytes. So you end up allocating too little memory.
Use this:
person->fname = malloc(strlen(fname)+1);
sizeof evaluates to the storage size of its argument (which might be an expression of a type, or just the type itself). So, look closely what the argument is here:
strlen(fname)+1
This is an expression of type size_t. sizeof will give you whatever amount of bytes is needed to store a size_t (probably either 4 or 8).
What you want is enough storage for your string, so the version with only strlen() is the correct one. In the other case, you reserve just 4 or 8 bytes and then write to memory locations you didn't allocate -> undefined behavior.
On a side note: casting void * is explicitly not needed in C and is considered bad practice by many (but not all) C coders. See this classic quesion.

Why this program is crashing did i wrongly allocated memory

This program is crashing. Please tell me what's wrong with it. When I use an array instead of a pointer like Name[12] in the structure it doesn't crash. I guess there is some problem in dynamic memory allocation. Help please.
#include <stdio.h>
struct struct_tag
{
int number;
char *Name;
} struct_name;
main()
{
struct_name.number = 34;
char *Name = (char *) malloc(sizeof(char));
strcpy(struct_name.Name,"A");
printf("%d", struct_name.number);
}
You're allocating a single character:
char *Name = (char *) malloc(sizeof(char));
And then never using that memory for anything. You meant to allocate memory for struct_name.Name, undoubtedly. But even if you had done so, you're then filling it with two characters ('a' and '\0'):
strcpy(struct_name.Name,"A");
which will cause an entirely different bug.
You want to say:
struct_name.Name = malloc( 2 );
Since (a) you shouldn't cast the result of malloc() and (b) sizeof(char) is always 1 and (c) you need room for the 0 at the end of your string.
For errors:
You are allocating memeory for *Name however you are not allocating
memory for struct_name.Name. So first thing is you need to allocate memory for struct_name.Name
As you already know that you'll be storing "A" in
struct_name.Name you should allocate memory for 2 char.("A" is string i.e 'A' and '\0')
For warnings:
If you want to use strcpy function include string.h in your code.
Also if you are using malloc include stdlib.h in your code.
Try this fixed code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct struct_tag
{
int number;
char *Name;
}struct_name;
int main()
{
struct_name.number = 34;
struct_name.Name = malloc(sizeof(char)*2); // As you will store "A"
strcpy(struct_name.Name,"A");
printf("%d \t", struct_name.number);
printf("%s \n", struct_name.Name);
return 0;
}
first look code carefully.
char *Name = (char *) malloc(sizeof(char));
strcpy(struct_name.Name,"A");
Hare for what you allocated memory (char *Name) and in which you copied string(struct_name.Name)?
here you not allocate memory for struct_name.Name. Also you have allocate memory for one character and you tried to copy two characters.('A' and '\0').
It should be
struct_name.Name = malloc(2);

c program dumping core on unix

I am a new learner of C language.
Below program run well on Windows but when i compile with gcc on solaris, this is dumping core
#include<stdio.h>
#include<stdlib.h>
void main()
{
char *name;
name="James Bond";
int i=0;
sprintf(name,"%s/%d",name,i);
printf("String is %s",name);
}
Please suggest
You cannot modify a string literal like that, it's undefined according to the standard. You're trying to overwrite that string literal with other data (the sprintf).
Many implementations will place them in read-only memory, causing a core dump - they're the good ones. The bad ones will continue on as if everything's okay, which it usually isn't.
You could try the following:
#include <stdio.h>
int main (void) {
char *name;
char name2[100]; // make sure plenty of space.
name = "James Bond";
int i = 0;
sprintf (name2, "%s/%d", name, i);
printf ("String is %s\n", name2);
return 0;
}
Most questions of this type have code like:
name = "Bob";
*name = 'J'; // to try and make "Job"
but it's just as undefined to write to string literals using sprintf as well.
Based on comments, you want to be able tocombine a path and file spec. You could do this as something like:
char *path = "/tmp/";
char *file = "xyz.txt"
char fullpath = malloc (strlen (path) + strlen (file) + 1);
if (fullpath == NULL)
// error and exit condition
strcpy (fullpath, path);
strcat (fullpath, file);
// use fullpath for your nefarious purposes :-)
free (fullpath);
That's one way to do it, there are others.
The correct way to define and initialize a constan string in C is
char name[]="James Bond";
Your code may be like this:
#include<stdio.h>
#include<stdlib.h>
void main()
{
char name[] = "James Bond";
int i = 0;
printf("String is %s/%d", name,i);
}
char *name;
name="James Bond"; // name is pointing into read-only memory
int i=0;
sprintf(name,"%s/%d",name,i); // trying to write to read-only memory
printf("String is %s",name);
instead use a buffer
char name[32] = "James Bond";
...
Your "name" string is insufficiently long to hold the set of characters you are printing to it with sprintf - you need to allocate a sufficient buffer for all of the characters.
You need to allocate memory for name pointer using malloc/calloc or defining it as a fixed length variable: char name[50] (for example)
On Linux and systems with the GNU Libc, you can also code using asprintf
char* str = NULL; // pointer should be initialized to NULL
asprintf (&str, "someformat %d", 20);
When using GTK, you could also call g_strdup_printf
You should understand the difference and similarities between arrays and pointers in C. Many many books or lectures explain that in detail.
Regards.

Resources