Passing string to struct in C [duplicate] - c

This question already has answers here:
Crash or "segmentation fault" when data is copied/scanned/read to an uninitialized pointer
(5 answers)
Closed 4 years ago.
I am complete beginner in C and need help with saving strings in structs.
(I tried multiple ways to have it done but program prints nothing or i got (0xC0000005) or program shuts down.. (I tried using pointer as a parameter but effect is the same-or using scanf straightly for text.line and etc ). I would be glad if somebody explained me simply how it should be done - I got feeling that i still dont fully understand idea of pointers and thats the problem ;q.
typedef struct label{
char *line;
}label;
void save_line(label text){
printf("Write your name\n");
char *helper=malloc(30 * sizeof *helper);
scanf("%s", helper);
strcpy(text.line, helper);
}
void main(){
label text;
save_line(text);
printf("%s", text.line);
}

When you pass a parameter to a function in C it creates a copy of it, so the text variable you have in main is not the same as the one you have in save_line.
You need to pass a pointer the text to save_line function, like so:
void save_line(label *text) {
printf("Write your name\n");
char *helper=malloc(30 * sizeof *helper);
scanf("%s", helper);
text->line = helper;
}
And in main:
void main(){
label text;
save_line(&text);
printf("%s", text.line);
}

There is no space to allocate your string in line, because it is just a no initialized pointer, so you will have to reserve some memory for it. Furthermore, your function is allocating memory which is not being deallocated (and regarding helper, you wouldn't need two different bunchs of memory for the same string).
#include<stdlib.h>
#include<stdio.h>
const uint8_t MAX_NAME_SIZE = 20;
typedef struct label{
char *line;
}label;
void save_line(label text){
printf("Write your name (max len %u chrs):\n",(MAX_NAME_SIZE-1));
scanf("%s", text.line);
}
void main(){
label text;
text.line = malloc(MAX_NAME_SIZE);
save_line(text);
printf("%s", text.line);
free(text.line);
}
I prefer to allocate and deallocate memory in the same scope, to avoid memory leaks (inside the same function, inside the main, etc), so in order to keep your structure, for the example the memory is being managed in the main. You should think about your design, and analyse the scope that label text; should have.

Your code is wrong at many levels:
You probably want something like this:
#include <stdio.h>
#include <stdlib.h>
typedef struct label {
char *line;
}label;
void save_line(label *text) { // use label *ttext instead of label text
printf("Write your name\n");
text->line = malloc(30 * sizeof *text->line); // no need for strcpy here anyway
scanf("%s", text->line);
}
int main() { // main should return int *
label text;
save_line(&text); // pass the pointer to text, not just text
printf("%s", text.line);
free(text.line); // free allocated memory
}
There is still room for improvement though, e.g. scanf("%s"), ... is dangerous because if the user types too many characters, you'll get a buffer overflow.
*read this: What should main() return in C and C++?

strcpy only copies the thing pointed to by the source to the destination. It does not allocate space in the destination for the stuff being copied.
If your platform has strdup you can use that instead:
text.line = strdup(helper);
If not, allocate some space in text.line before you strcpy
text.line = malloc(strlen(helper) + 1); // +1 for the null byte at the end
strcpy(text.line, helper);

Related

Dynamically expanding C code without using realloc

I need to put the names separated by commas from the text into struct that expands dynamically, but I am prohibited from using realloc ().I'm getting a core dumped error in this code. What is the error in this code?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct movie{
double budget;
int genre;
char* name;
double score;
int year;
};
void recorder_function(struct movie *movies){
FILE*fp;
fp=fopen("Movies.txt","r");
struct movie *p;
int i,n=0;
char line[1000];
char temp_budget[50];
char temp_name[50];
char temp_genre[50];
while (!feof(fp)) {
fgets(line,1000,fp);
sscanf(line,"%50[^,],%50[^,],%50[^,]",temp_budget,temp_genre,temp_name);
//I open the fields in this section
movies=(struct movie *)calloc(n+1,sizeof(struct movie));
p=(struct movie *)calloc(n+1,sizeof(struct movie));
p[n].name=(char*)malloc(sizeof(char)*(strlen(temp_name)+1));
movies[n].name=(char*)malloc(sizeof(char)*(strlen(temp_name)+1));
for(i=0;i<n;i++)
movies[i]=p[i];
strcpy(movies[n].name,temp_name);
free(p);
p=movies;
n++;
}
for(i=0;i<n;i++)
printf("%s\n",movies[i].name);
}
int main(){
int choice;
struct movie *movies;
recorder_function(movies);
}
It is a bad idea to overwrite the pointer movie by newly allocated clean buffer.
Instead of that, you should
Allocate new buffer only for p.
Put the new element to p[n]
Put existing elements movie[0], ... , movie[n-1] to p[0], ... , p[n-1]
Free the old buffer movie
Assign the new buffer p to movie
Don't forget to initialize movie not to cause troubles at the first freeing.
Also while (!feof(fp)) is wrong and you should check if readings are successful after trying to read and before using what are read.
One more important point is that you should make sure that fopen() succeeded. Passing NULL, which fopen() returns on failure`, to other file manipulation functions may cause troubles.
Another point is that your arrays used for sscanf() outputs should have one more elements for the terminating null-character.
Yet another point is that casting results of malloc() family is considered as a bad practice.
Try this:
void recorder_function(struct movie *movies){
FILE*fp;
fp=fopen("Movies.txt","r");
if(fp==NULL){
fputs("file open error\n", stderr);
return;
}
struct movie *p;
int i,n=0;
char line[1000];
char temp_budget[51];
char temp_name[51];
char temp_genre[51];
movies=NULL;
while (fgets(line,1000,fp)) {
sscanf(line,"%50[^,],%50[^,],%50[^,]",temp_budget,temp_genre,temp_name);
//I open the fields in this section
p=calloc(n+1,sizeof(struct movie));
p[n].name=malloc(sizeof(char)*(strlen(temp_name)+1));
strcpy(p[n].name,temp_name);
for(i=0;i<n;i++){
p[i]=movies[i];
}
free(movies);
movies=p;
n++;
}
for(i=0;i<n;i++){
printf("%s\n",movies[i].name);
}
}
The next stage will be fixing the weird usage of the argument movie. Arguments in C are copies of what are passed, and modifications of arguments in callee functions won't affect what are passed in caller. Your choice is:
Remove the argument movies and convert that to a local variable.
Have recorder_function take a pointer to struct movie* (struct movie**) and have it use the pointer to modify what caller specifies. (You also have to change the statement to call the function to pass a pointer in this case)

Taking string input in char pointer

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(){
char *s;
printf("enter the string : ");
scanf("%s", s);
printf("you entered %s\n", s);
return 0;
}
When I provide small inputs of length up to 17 characters (for example "aaaaaaaaaaaaaaaaa") the program works perfectly fine but on providing inputs of larger lengths, it gives me a runtime error saying "main.c has stopped working unexpectedly".
Is there some problem with my compiler (codeblocks) or my pc (windows 7)? Or is it somehow related to the input buffer of C?
It's undefined behaviour as the pointer is uninitialized. There's no problem with your compiler but your code has problem :)
Make s point to valid memory before storing data in there.
To manage buffer overflow, you can specify the length in the format specifier:
scanf("%255s", s); // If s holds a memory of 256 bytes
// '255' should be modified as per the memory allocated.
GNU C supports an non-standard extension with which you don't have to allocate memory as allocation is done if %as is specified but a pointer to pointer should be passed:
#include<stdio.h>
#include<stdlib.h>
int main() {
char *s,*p;
s = malloc(256);
scanf("%255s", s); // Don't read more than 255 chars
printf("%s", s);
// No need to malloc `p` here
scanf("%as", &p); // GNU C library supports this type of allocate and store.
printf("%s", p);
free(s);
free(p);
return 0;
}
the char pointer is not initialized, you should dynamiclly allocate memory to it,
char *s = malloc(sizeof(char) * N);
where N is the maximum string size you can read, And its not safe to use scanf
without specifying the maximum length for the input string, use it like this,
scanf("%Ns",s);
where N same as that for malloc.
You are not allocating any memory to the character array so first try to get memory by calling malloc() or calloc(). then try to use it.
s = malloc(sizeof(char) * YOUR_ARRAY_SIZE);
...do your work...
free(s);
You need to allocate enough memory for buffer where your pointer will point to:
s = malloc(sizeof(char) * BUF_LEN);
and then free this memory if you do not need it anymore:
free(s);
You're not allocating memory for your string, and thus, you're trying to write in a non-authorized memory address. Here
char *s;
You're just declaring a pointer. You're not specifying how much memory to reserve for your string. You can statically declare this like:
char s[100];
which will reserve 100 characters. If you go beyond 100, it will still crash as you mentionned for the same reason again.
The problem is with your code .. you never allocate memory for the char *. Since, there is no memory allocated(with malloc()) big enough to hold the string, this becomes an undefined behavior..
You must allocate memory for s and then use scanf()(I prefer fgets())
#include"stdio.h"
#include"malloc.h"
int main(){
char *str;
str=(char*)malloc(sizeof(char)*30);
printf("\nENTER THE STRING : ");
fgets(str,30,stdin);
printf("\nSTRING IS : %s",str);
return 0;
}
The code in C to read a character pointer
#include<stdio.h>
#include<stdlib.h>
void main()
{
char* str1;//a character pointer is created
str1 = (char*)malloc(sizeof(char)*100);//allocating memory to pointer
scanf("%[^\n]s",str1);//hence the memory is allocated now we can store the characters in allocated memory space
printf("%s",str1);
free(str1);//free the memory allocated to the pointer
}
I was getting this problem. I tried this code below and it worked:
char *text;
scanf("%s", *&text);
I dont know how it worked. I just felt like doing it.

Can't declare two character pointers [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
why does c allow initialization of string without declaration?
I am trying this rather simple code:
#include<stdio.h>
void copy(char *,char *);
main() {
char *name;
char *surname;
printf("Enter name: ");
scanf("%s",name);
printf("%s",name);
}
But for some reason, after I enter a name and press Enter, the program hangs and gives a message like Program has stopped working. However when I remove the 2nd character pointer declaration, that is the char *surname;, it works just as expected. What is the problem here?
You have not allocated memory for the pointers, so the scanf accesses arbitrary unspecified memory, which is undefined behaviour.
You need to pass pointers to sufficiently large memory blocks to scanf, either declare
char s1[100], s2[100];
(if 100 is large enough), or malloc memory
char *s1 = malloc(100);
char *s2 = malloc(100);
if (!s1 || !s2) {
// malloc failure
exit(EXIT_FAILURE);
}
You are writting into unallocated memory. That is undefined behavior,
You can do 2 things here:
declare your arrays of chars as having a fixed size at compile-time like this: char name[100]; (which means you can't change their size at runtime)
allocate room for char *name using malloc() or calloc() functions in stdlib.h
In any case you absolutely have to make sure you only allow the user to input the amount of bytes you allocated, otherwise bad things can and will happen!
A small study on what an evil person can (and will ;) do if you fail to define said boundaries can be found here: http://www.cultdeadcow.com/cDc_files/cDc-351/
Because you didn't allocate memory for it, and the string you put in it screws the code of the program. Try to use sscanf and getline:
#include <stdio.h>
int main()
{
int nbytes = 100;
char *my_string;
int int1, int2, int3;
int args_assigned;
args_assigned = 0;
while (args_assigned != 3)
{
puts ("Please enter three integers separated by whitespace.");
my_string = (char *) malloc (nbytes + 1);
getline (&my_string, &nbytes, stdin);
args_assigned = sscanf (my_string, "%d %d %d", &int1, &int2, &int3);
if (args_assigned != 3)
puts ("\nInput invalid!");
}
printf ("\nThanks!\n%d\n%d\n%d\n", int1, int2, int3);
return 0;
}
check out this:
Reading in a variable length string user input in C
and this :
http://en.wikipedia.org/wiki/Buffer_overflow
You declare a pointer and do not give it a valid memory address, it points to a random addrss. You cannot read or write with this pointer. Pointers should be used like this:
char s1[100],s2[100];
char * name=s1;
char * surname=s2;

Malloc and scanf

I'm fairly competent in a few scripting languages, but I'm finally forcing myself to learn raw C. I'm just playing around with some basic stuff (I/O right now). How can I allocate heap memory, store a string in the allocated memory, and then spit it back out out? This is what I have right now, how can I make it work correctly?
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char *toParseStr = (char*)malloc(10);
scanf("Enter a string",&toParseStr);
printf("%s",toParseStr);
return 0;
}
Currently I'm getting weird output like '8'\'.
char *toParseStr = (char*)malloc(10);
printf("Enter string here: ");
scanf("%s",toParseStr);
printf("%s",toParseStr);
free(toParseStr);
Firstly, the string in scanf is specifies the input it's going to receive. In order to display a string before accepting keyboard input, use printf as shown.
Secondly, you don't need to dereference toParseStr since it's pointing to a character array of size 10 as you allocated with malloc. If you were using a function which would point it to another memory location, then &toParseStr is required.
For example, suppose you wanted to write a function to allocate memory. Then you'd need &toParseStr since you're changing the contents of the pointer variable (which is an address in memory --- you can see for yourself by printing its contents).
void AllocateString(char ** ptr_string, const int n)
{
*ptr_string = (char*)malloc(sizeof(char) * n);
}
As you can see, it accepts char ** ptr_string which reads as a pointer which stores the memory location of a pointer which will store the memory address (after the malloc operation) of the first byte of an allocated block of n bytes (right now it has some garbage memory address since it is uninitialized).
int main(int argc, char *argv[])
{
char *toParseStr;
const int n = 10;
printf("Garbage: %p\n",toParseStr);
AllocateString(&toParseStr,n);
printf("Address of the first element of a contiguous array of %d bytes: %p\n",n,toParseStr);
printf("Enter string here: ");
scanf("%s",toParseStr);
printf("%s\n",toParseStr);
free(toParseStr);
return 0;
}
Thirdly, it is recommended to free memory you allocate. Even though this is your whole program, and this memory will be deallocated when the program quits, it's still good practice.
You need to give scanf a conversion format so it knows you want to read a string -- right now, you're just displaying whatever garbage happened to be in the memory you allocated. Rather than try to describe all the problems, here's some code that should at least be close to working:
char *toParseStr = malloc(10);
printf("Enter a string: ");
scanf("%9s", toParseStr);
printf("\n%s\n", toParsestr);
/* Edit, added: */
free(toParseStr);
return 0;
Edit: In this case, freeing the string doesn't make any real difference, but as others have pointed out, it is a good habit to cultivate nonetheless.
Using scanf() (or fscanf() on data you don't control) with a standard "%s" specifier is a near-certain way to get yourself into trouble with buffer overflows.
The classic example is that it I enter the string "This string is way more than 10 characters" into your program, chaos will ensue, cats and dogs will begin sleeping together and a naked singularity may well appear and consume the Earth (most people just state "undefined behaviour" but I think my description is better).
I actively discourage the use of functions that cannot provide protection. I would urge you (especially as a newcomer to C) to use fgets() to read your input since you can control buffer overflows with it a lot easier, and it's more suited to simple line input than scanf().
Once you have a line, you can then call sscanf() on it to your heart's content which, by the way, you don't need to do in this particular case since you're only getting a raw string anyway.
I would use:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFSZ 10
int main(int argc, char *argv[]) {
char *toParseStr = malloc(BUFFSZ+2);
if (toParseStr == NULL) {
printf ("Could not allocate memory!\n");
return 1;
}
printf ("Enter a string: ");
if (fgets (toParseStr, BUFFSZ+2, stdin) == NULL) {
printf ("\nGot end of file!\n");
return 1;
}
printf("Your string was: %s",toParseStr);
if (toParseStr[strlen (toParseStr) - 1] != '\n') {
printf ("\nIn addition, your string was too long!\n");
}
free (toParseStr);
return 0;
}
You don't need an & before toParseStr in scanf as it is already a pointer
also call free(toParseStr) afterwards
First, the errors that was keeping your program from working: scanf(3) takes a format-string, just like printf(3), not a string to print for the user. Second, you were passing the address of the pointer toParseStr, rather than the pointer toParseStr.
I also removed the needless cast from your call to malloc(3).
An improvement that your program still needs is to use scanf(3)'s a option to allocate memory for you -- so that some joker putting ten characters into your string doesn't start stomping on unrelated memory. (Yes, C will let someone overwrite almost the entire address space with this program, as written. Giant security flaw. :)
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char *toParseStr = malloc(10);
printf("Enter a short string: ");
scanf("%s",toParseStr);
printf("%s\n",toParseStr);
return 0;
}

this code, its work fine and return what i want, but its hangs before print it?

I make this program ::
#include<stdio.h>
char *raw_input(char *msg);
main() {
char *s;
*s = *raw_input("Message Here Is: ");
printf("Return Done..");
printf(s);
}
char *raw_input(char *msg){
char *d;
printf("%s", msg);
scanf("%s",&d);
return d;
}
What this do is, it print my message and scan for input from the user, then print it,, but whats the problem in print the input from the user ???
Update::
I need the raw_input func. call be like this without any extra
*s = *raw_input("Message Here");
I dont want to use this ::
raw_input("Message Here Is: ", d);
....
Just want to return the string that the user will enter .
Update2::
from jamesdlin Answer( Thank You ),,Now its clear to my that's my problem was in how to return an allocated string in this :)
#include<stdio.h>
#define buffer 128
char *raw_input(char *msg);
main() {
char *s;
s = raw_input("Message Here Is: ");
printf("%s\n",s);
}
char *raw_input(char *msg){
char *d;
printf("%s", msg);
fflush(stdout);
fgets(d, buffer, stdin); ## In this there is a problem
return d;
}
now when i start this program its print the message and then just exit(end)the program without taking any word from the user ???
You don't allocate memory for d, so using it in scanf leads to undefined behaviour.
Actually, it's even worse than that: you pass the address of d to scanf, which is then filled with the integer read from console. In effect, you initialize a pointer with an integer value, so the pointer points to somewhere out in the jungle. Thus dereferencing it is undefined behaviour. [Update]: even this is not all: as #Heath pointed out below, this in fact allows you to corrupt your call stack by entering a sufficiently long input on the console :-((( [/Update]
Not to mention that you are trying to return a local variable from your function, which is destroyed as soon as it gets out of scope. This should work better:
void raw_input(char *msg, char *d);
main() {
char d[128];
raw_input("Message Here Is: ", d);
printf("Return Done..");
printf(d);
}
void raw_input(char *msg, char *d){
printf("%s", msg);
scanf("%s", d);
}
Fair enough, this does not prevent buffer overflow... but it is enough to ilustrate my point.
Update: so you want to return an allocated string (i.e. a char* pointer) from raw_input() in any case. AFAIK you have 3 choices:
return a pointer passed in by the caller as a parameter (a slight extension of my example above): this is the one I would prefer. However, this requires an extra function parameter (in fact 2, since we should also pass in the length of the buffer in a proper solution to avoid buffer overflows). So if you absolutely need to stick to the function signature shown above, this isn't an option.
return a pointer to a static / global buffer visible to both caller and callee: this is a variation of the above, to avoid modifying the function signature. The downside is that the code is more difficult to understand and maintain - you don't know that the function modifies a static / global variable without actually looking at its implementation. This in turn also makes unit testing more difficult.
return a pointer to a buffer allocated inside the function - although technically possible, this is the worst option, since you effectively pass on the ownership of the buffer; in other words, the caller must remember to free the buffer returned. In a simple program like the one you showed above, this may not seem like a big issue, but in a big program, that buffer may be passed around to far away places within the app, so there is a high risk that noone frees it in the end, thus leaking memory.
The pointer d in the function is uninitialized. scanf would be filling up arbitrary memory. Instead, you need to pass a buffer (character array) for it to fill, and the buffer has to be defined in main, otherwise it'll be destroyed before you can return it (unless you do dynamic allocation, but that's another story).
#include<stdio.h>
char *raw_input(char *msg);
int main() {
char *s;
s = raw_input("Message Here Is: ");
printf("Return Done..");
printf("%s", s);
free(s);
return 0;
}
char *raw_input(char *msg){
char *d;
d = malloc(20)
if(d==0) return 0;
printf("%s", msg);
scanf("%19s", d);
return d;
}
Try this, should work. The other answers pointed your errors out, as I can see... I was to slow ;)
EDIT: Ok, found an error... fixed it ;)
EDIT2:
Max suggested a struct was possible, here is some code:
#include<stdio.h>
struct mystring{
char str[20];
};
struct mystring raw_input(char *msg);
int main() {
struct mystring input;
input = raw_input("Message Here Is: ");
printf("Return Done..");
printf("%s", input.str);
return 0;
}
struct mystring raw_input(char *msg){
struct mystring input;
printf("%s", msg);
scanf("%19s", input.str);
return input;
}
As mentioned, you aren't allocating memory for use with scanf. But never ever use scanf; it's hard to use correctly and to avoid buffer overflows. Use fgets.
From the comp.lang.c FAQ: Why does everyone say not to use scanf? What should I use instead?
Also, while unrelated to your problem, this bit of code is dangerous:
*s = *raw_input("Message Here Is: ");
printf("Return Done..");
printf(s);
You are passing user-input directly to printf as a format strings, so this is susceptible to format string attacks if the printed string happens to include % characters. Better:
*s = *raw_input("Message Here Is: ");
printf("Return Done..");
printf("%s\n", s);
Also, you might want some newlines when you print. Also:
*s = *raw_input("Message Here Is: ");
won't work because s doesn't point to anything, so you're dereferencing a garbage pointer. Assuming that you fix raw_input to return an allocated string, it should be:
s = raw_input("Message Here Is: ");
Lastly (also unrelated to your problem):
char *raw_input(char *msg){
char *d;
printf("%s", msg);
scanf("%s",&d);
return d;
}
You should call fflush(stdout) after printing the prompt. See My program's prompts and intermediate output don't always show up on the screen, especially when I pipe the output through another program.
Try this experiment:
#include<stdio.h>
char *raw_input(char *msg);
main() {
char *s;
s = raw_input("Message Here Is: ");
printf("Return Done..");
printf(s);
}
char *raw_input(char *msg)
{
int value = 0;
char *d;
printf("%s", msg);
scanf("%s",&d);
if (value)
printf("value has become %08X\n", value);
return d;
}
Perform several experiements with input messages as long as: 3, 4, 5, 7, 8, 9, 11, 12, 13, etc. characters long. See what the result is for the integer variable value. You will see that due to your misuse of scanf() by passing the address of d, you are allowing scanf() to destroy local variables of your function, including the return address.
And that gets us back to the name of this web site.
You can not return a pointer of a variable that has been created inside the function. The variable d is not valid anymore in the main function.
try this:
1. create the variable d in the main function
2. and pass it to the raw_input function
void raw_input(char *msg, char *d)

Resources