Can I use a pointer as the parameter of gets in C? - c

I am studying the C language.
When I pass a pointer to gets(), I find it can work well.
char *ptr;
gets(ptr);
puts(ptr);
But if I define an array of pointers, it doesn't work.
char *ptr[4];
int i=0;
for(i=0;i<4;++i)
gets(ptr[i]);
for(i=0;i<4;++i)
puts(ptr[i]);
Are they different, or is the first part wrong in fact? I want to know the reason.

You pass a pointer to a function (e.g. gets()) that writes data to a memory location pointed by your pointer. In your case, you have the uninitialized pointer, which means it points to a random memory location (where applications or an operating system resides). This leads to random effects - from "working" to abnormal termination or hanging. You need to reserve memory and assign pointer to point there, e.g. by:
char *ptr = (char*)malloc(256);
gets(ptr);
puts(ptr);
free(ptr);
Consider to use gets_s() that is more secure.

char *ptr[4];
int i=0;
for(i=0;i<4;++i)
gets(ptr[i]);
This is not valid C code as you did not allocate space for ptr[i]. On the other hand, never use gets because it's a function that does not check for buffer limit.

The pointer has to point somewhere first.
#define BUFSIZE 100
char *ptr = malloc(BUFSIZE);
fgets(stdin, ptr, BUFSIZE);
puts(ptr);
char *ptr[4];
int i=0;
for(i=0;i<4;++i) {
ptr[i] = malloc(BUFSIZE);
fgets(ptr[i], BUFSIZE, stdin);
}
for(i=0;i<4;++i) {
puts(ptr[i]);
}

Related

Can someone explain why I'm getting segmentation fault 11?

Here is my code:
int main() {
typedef struct {
int recordCount;
char *firstName;
char *secondName;
char *id;
char *email;
}student;
student *students = malloc(sizeof(*students));
int i = 0;
while (students[i].firstName[0] != '.'){
students[i].firstName = (char *)malloc(sizeof(char*));
scanf("%s", students[i].firstName);
i++;
students = realloc(students, sizeof(students) * (i + 1));
}
}
When I run it through a for loop it works, I'm pretty sure it's just something silly going on with my while loop.
malloc returns a block of uninitialized memory. So students[i].firstName is an uninitialized pointer which you attempt to dereference. Reading and dereferencing an uninitialized pointer invokes undefined behavior, which in this case manifests as a crash.
When you do allocate space for the firstName member, you only allocate sizeof(char*) bytes for it which is the size of a pointer, not necessarily the length of a string you would want to read.
Create a buffer to read strings into that's big enough for what you might need, then use strdup to create a copy to assign to the relevant pointer.
student *students = NULL;
int i = 0;
char str[100];
scanf("%99s", str);
while (str[0] != '.'){
students = realloc(students, sizeof(*students) * (i+1));
students[i].firstName = strdup(str);
i++;
scanf("%99s", str);
}
For a start,
students[i].firstName = (char *)malloc(sizeof(char*));
allocates enough space for a character pointer, typically four or eight bytes.
While there are some names that will fit in that (such as Pax or Bob), the vast majority probably won't.
You need to allocate enough space for the largest name (and string terminator), such as with:
#define MAX_NAME_LEN 100
students[i].firstName = malloc(MAX_NAME_LEN + 1);
There are plenty of issues in your code.
When you are using malloc, you actually specify the data type and not the pointer type which is I believe is not your intent here. If you are specifying a pointer type with sizeof, the pointer will point to a memory location having the size of the pointer. This is not what you want in this case.
After the line student *students = malloc ... . The students will point to a memory location which will hold zero values in firstName. You need to use malloc for these. Since you are not doing this you are getting a segmentation fault because you are dereferencing an invalid pointer (pointing to location 0). You are trying to access it first and using malloc afterwards.
If you
student *students = malloc(sizeof(*students));
you are allocating size of one pointer. What you want to do is instead
student *students = malloc(sizeof(students));
and for the same reason, students[i].firstName = (char *)malloc(sizeof(char*)) quite surely do not have enough memory for your name as well, try malloc(sizeof(char)*100) or so.

Memory, pointers, and pointers to pointers

I am working on a short program that reads a .txt file. Intially, I was playing around in main function, and I had gotten to my code to work just fine. Later, I decided to abstract it to a function. Now, I cannot seem to get my code to work, and I have been hung up on this problem for quite some time.
I think my biggest issue is that I don't really understand what is going on at a memory/hardware level. I understand that a pointer simply holds a memory address, and a pointer to a pointer simply holds a memory address to an another memory address, a short breadcrumb trail to what we really want.
Yet, now that I am introducing malloc() to expand the amount of memory allocated, I seem to lose sight of whats going on. In fact, I am not really sure how to think of memory at all anymore.
So, a char takes up a single byte, correct?
If I understand correctly, then by a char* takes up a single byte of memory?
If we were to have a:
char* str = "hello"
Would it be say safe to assume that it takes up 6 bytes of memory (including the null character)?
And, if we wanted to allocate memory for some "size" unknown at compile time, then we would need to dynamically allocate memory.
int size = determine_size();
char* str = NULL;
str = (char*)malloc(size * sizeof(char));
Is this syntactically correct so far?
Now, if you would judge my interpretation. We are telling the compiler that we need "size" number of contiguous memory reserved for chars. If size was equal to 10, then str* would point to the first address of 10 memory addresses, correct?
Now, if we could go one step further.
int size = determine_size();
char* str = NULL;
file_read("filename.txt", size, &str);
This is where my feet start to leave the ground. My interpretation is that file_read() looks something like this:
int file_read(char* filename, int size, char** buffer) {
// Set up FILE stream
// Allocate memory to buffer
buffer = malloc(size * sizeof(char));
// Add characters to buffer
int i = 0;
char c;
while((c=fgetc(file))!=EOF){
*(buffer + i) = (char)c;
i++;
}
Adding the characters to the buffer and allocating the memory is what is I cannot seem to wrap my head around.
If **buffer is pointing to *str which is equal to null, then how do I allocate memory to *str and add characters to it?
I understand that this is lengthy, but I appreciate the time you all are taking to read this! Let me know if I can clarify anything.
EDIT:
Whoa, my code is working now, thanks so much!
Although, I don't know why this works:
*((*buffer) + i) = (char)c;
So, a char takes up a single byte, correct?
Yes.
If I understand correctly, by default a char* takes up a single byte of memory.
Your wording is somewhat ambiguous. A char takes up a single byte of memory. A char * can point to one char, i.e. one byte of memory, or a char array, i.e. multiple bytes of memory.
The pointer itself takes up more than a single byte. The exact value is implementation-defined, usually 4 bytes (32bit) or 8 bytes (64bit). You can check the exact value with printf( "%zd\n", sizeof char * ).
If we were to have a char* str = "hello", would it be say safe to assume that it takes up 6 bytes of memory (including the null character)?
Yes.
And, if we wanted to allocate memory for some "size" unknown at compile time, then we would need to dynamically allocate memory.
int size = determine_size();
char* str = NULL;
str = (char*)malloc(size * sizeof(char));
Is this syntactically correct so far?
Do not cast the result of malloc. And sizeof char is by definition always 1.
If size was equal to 10, then str* would point to the first address of 10 memory addresses, correct?
Yes. Well, almost. str* makes no sense, and it's 10 chars, not 10 memory addresses. But str would point to the first of the 10 chars, yes.
Now, if we could go one step further.
int size = determine_size();
char* str = NULL;
file_read("filename.txt", size, &str);
This is where my feet start to leave the ground. My interpretation is that file_read() looks something like this:
int file_read(char* filename, int size, char** buffer) {
// Set up FILE stream
// Allocate memory to buffer
buffer = malloc(size * sizeof(char));
No. You would write *buffer = malloc( size );. The idea is that the memory you are allocating inside the function can be addressed by the caller of the function. So the pointer provided by the caller -- str, which is NULL at the point of the call -- needs to be changed. That is why the caller passes the address of str, so you can write the pointer returned by malloc() to that address. After your function returns, the caller's str will no longer be NULL, but contain the address returned by malloc().
buffer is the address of str, passed to the function by value. Allocating to buffer would only change that (local) pointer value.
Allocating to *buffer, on the other hand, is the same as allocating to str. The caller will "see" the change to str after your file_read() returns.
Although, I don't know why this works: *((*buffer) + i) = (char)c;
buffer is the address of str.
*buffer is, basically, the same as str -- a pointer to char (array).
(*buffer) + i) is pointer arithmetic -- the pointer *buffer plus i means a pointer to the ith element of the array.
*((*buffer) + i) is dereferencing that pointer to the ith element -- a single char.
to which you are then assigning (char)c.
A simpler expression doing the same thing would be:
(*buffer)[i] = (char)c;
with char **buffer, buffer stands for the pointer to the pointer to the char, *buffer accesses the pointer to a char, and **buffer accesses the char value itself.
To pass back a pointer to a new array of chars, write *buffer = malloc(size).
To write values into the char array, write *((*buffer) + i) = c, or (probably simpler) (*buffer)[i] = c
See the following snippet demonstrating what's going on:
void generate0to9(char** buffer) {
*buffer = malloc(11); // *buffer dereferences the pointer to the pointer buffer one time, i.e. it writes a (new) pointer value into the address passed in by `buffer`
for (int i=0;i<=9;i++) {
//*((*buffer)+i) = '0' + i;
(*buffer)[i] = '0' + i;
}
(*buffer)[10]='\0';
}
int main(void) {
char *b = NULL;
generate0to9(&b); // pass a pointer to the pointer b, such that the pointer`s value can be changed in the function
printf("b: %s\n", b);
free(b);
return 0;
}
Output:
0123456789

Save pointer's memory address

I have to implement a function that returns the memory address of a pointer when I allocate it with malloc(). I know that malloc(value) allocates an area on the heap which is of size value.
I know how to implement the code for printing the memory address of that pointer:
void *s = malloc (size)
printf("%p\n",s);
My question is, how can I save the value printed by that code in an int or string (e.g. char *)?
Storing the value of the pointer (i.e. the memory location of some variable) in a string can be done much like you've used printf:
char buf[128];
void *s = malloc (size);
sprintf(buf, "%p\n",s);
To 'save' the value into an integer (type) you can do a simple cast:
void *s = malloc (size);
size_t int_value = (size_t)s;
Since in c you never know what your machine address pointer length is, this (technically) isn't guaranteed to work quite right; both of these methods can go wrong with wacky architectures or compilers.
char buf[32] = {0}
snprintf(buf, sizeof buf, "%p\n", s);
then you can print it:
printf("%s\n", buf);
You've already saved the value as a bit pattern in s, so I assume you mean that you simply want the text output by printf as a string. The call you want is sprintf:
char text[255];
sprintf(text, "%p\n", s);
If you want the pointer address returned from your function, you can declare your function to return the pointer type:
int* myFunc(int n) {
int* p;
p = malloc(n*sizeof(int));
// more stuff
return p;
}
This is an alternative to the use of sprintf as suggested (very reasonably) by other answers.
Take your pick.
Note that on some systems an int would not be big enought to hold a int* data type - using int* is not only clearer but safer as well.
Yes sprintf() is the best option. Here you can simply take any thing inside a string.

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.

Is there different about the following memory allocation?

There are four ways to dynamic allocate memory, is there differences among the four ways?
first like this:
char *seq=(char *)malloc(100*sizeof(char));
void exam(char *seq){
// using 'seq'
}
second like this:
char *seq;
void exam(char *seq){
seq=(char *)malloc(100*sizeof(char));
// using 'seq'
}
third like this:
char *seq=(char *)malloc(10*sizeof(char));
void exam(char *seq){
char *change=(char *)malloc(100*sizeof(char));
free(seq);
seq=change;
// using 'seq'
}
fourth like this:
char *seq=(char *)malloc(100*sizeof(char));
void exam(char *seq){
free(seq);
seq=(char *)malloc(100*sizeof(char));
//using 'seq'
}
and you should konw that, I will use the variable 'seq' outside of the method 'exam'.
please explain the above codes, thank you very much.
Only the first case is valid if you intend to use seq outside of exam.
The other three cases receive the address allocated for seq, but are unable to change it.
To change the value of seq, you need to either return a new value for it, or explicitly modify what's in seq.
You need to investigate Pass by Value to understand why this doesn't work. See this page.
You should not cast the result of malloc() unless you're using an implementation of C that predates the 1989 ANSI standard, or you intend to compile this code as C++, in which case you should be using new instead of malloc(); first of all, it isn't necessary, and second of all, it will mask a compiler diagnostic if you don't have a prototype for malloc() in scope.
Also, sizeof(char) is 1 by definition; using it in this case makes no difference and just adds visual noise.
The canonical form for writing a malloc() statement for any type T is
T *p = malloc(count * sizeof *p);
or
T *p;
...
p = malloc(count * sizeof *p);
Now addressing your four cases...
Your first case is generally correct; you're allocating the memory for seq outside of exam, and passing the pointer by value.
Your remaining cases all have a similar problem; the change to the pointer value seq is not going to be reflected in the caller, and you will have introduced a memory leak. If you're passing a pointer to a function, and you want the pointer value to be overwritten, then you need to pass a pointer to that pointer:
char *seq;
exam(&seq);
...
void exam(char **seq) { *seq = malloc(100); ... }
If you want to resize a dynamically allocated buffer, use realloc():
char *seq = malloc(10);
exam(&seq);
...
void exam(char **seq)
{
char *tmp = realloc(*seq, 100);
if (!tmp)
{
/* realloc failed */
}
else
{
*seq = tmp;
...
}
Note that
char *p = realloc(NULL, 10);
is the same as
char *p = malloc(10);
There are probably many ways to do what your doing. If you intend on using seq outside of the function, the first method you outlined will work.
The other methods you have have other issues if you intend on using seq after calling the function. Since C is pass by value, you are passing the address contained in seq to the routine, which will not change the memory location associated with seq in the last three examples. To change the memory location of seq, you need to pass the address of the pointer into the routine to set the pointer. This is shown in David Cournapeau example.
The issue with the last two cases is that you "freed" the memory, but you are still retaining a pointer to the memory as the value of seq will not be changed and you can use it to access memory you have "freed". This is known a a dangling pointer.
David Cournapeau suggestion of using a function to return the pointer would give you access to the memory you allocated in the function. Otherwise you will need to pass the address of seq into the routine and dereference the value to set it to the allocated space.
It all depends on what you are trying to do. If possible, it is better to do malloc/free in the same scope, IMO, it makes the code much more readable - memory allocation in C is already hard enough. In your case, you would first malloc, call the function, and free after outside the function. But of course, it is not always possible.
Some of your solutions will not work: the second one, for example, will not do what you want, because when you call the function, the pointer is copied:
char *p;
function(p);
void function(char *q) {
// q is a copy of p, so when q is set by malloc, it will not be reflected in p
q = malloc(100);
}
Generally, you should do as the fopen functions: you return a pointer:
char* p function() {
char* ret;
ret = malloc(100);
return ret;
}
char *p = function();
Or you could use a pointer to a pointer:
char *p;
function(&p);
void function(char **q) {
// q is a copy of &p, so when *q is set by malloc, it is the same memory location as &p
*q = malloc(100);
}
I think the first one is much better, though, in general.
Also, concerning your style: sizeof(char) is useless, it is always equal to 1 by definition, whatever compiler/platform you are using, and casting the malloc is useless and actually dangerous (because it hides missing header inclusion where malloc is declared). It is only useful if you use malloc in C++ (where the cast is mandatory).
I think these are differences in scope
To cast some light on the situation, consider this rewriting:
char *seq=(char *)malloc(100*sizeof(char));
void exam(char *var){
// using 'var'
}
//--
char *seq;
void exam(char *var){
var=(char *)malloc(100*sizeof(char));
// using 'var'
}
//--
char *seq=(char *)malloc(10*sizeof(char));
void exam(char *var){
char *change=(char *)malloc(100*sizeof(char));
free(var);
var=change;
// using 'var'
}
//--
char *seq=(char *)malloc(100*sizeof(char));
void exam(char *var){
free(var);
var=(char *)malloc(100*sizeof(char));
//using 'var'
}
When you call
exam(seq);
the above versions are identical to your original.

Resources