I was trying to scan a string input from the user and then print it in the next line, but I'm not able to figure out, as I'm new to coding, why it is showing no output! Below is the code-
main()
{
char* w1,w2,w3,e1,e2,e3;
printf("List of Words");
printf("\tMeanings");
scanf("%s",&w1);
printf("\n%s",w1);
getch();
}
I expected w1 to print under "List of Words" but it isn't showing any output.
Here
char* w1; /* uninitialized pointer */
scanf("%s",&w1); /* for w1 no memory is allocated. Also & is not required since w1 tends to points to some address */
w is character pointer and pointer needs to point to some valid memory location, but in your case w1 not having any valid memory.
Allocate memory for w first and then put the input data into w using scanf(). For e.g
#define BUF_MAX_LENGTH 10
char *w1 = malloc(BUF_MAX_LENGTH);
if(w1 == NULL) {
/* #TODO error handling */
}
And then scan the data into w1. For e.g
scanf("%s", w1);
And once usage is done with w do not forget to free the dynamically allocated memory to avoid memory leakage. For e.g
free(w1);
Side note, do avoid declaring character variable & character pointer variable in same declaration to improve code readability. For e.g
char* w1,w2,w3,e1,e2,e3; /* mixed up */
can be
char* w1 = NULL; /* All pointer declaration */
char w2,w3,e1,e2,e3; /* All normal char variable */
Related
When we allocating memory spaces for a string, do the following 2 ways give the same result?
char *s = "abc";
char *st1 = (char *)malloc(sizeof(char)*strlen(s));
char *st2 = (char *)malloc(sizeof(s));
In other words, does allocate the memory based on the size of its characters give the same result as allocating based on the size of the whole string?
If I do use the later method, is it still possible for me to add to that memory spaces character by character such as:
*st = 'a';
st++;
*st = 'b';
or do I have to add a whole string at once now?
Let's see if we can't get you straightened out on your question and on allocating (and reallocating) storage. To begin, when you declare:
char *s = "abc";
You have declared a pointer to char s and you have assigned the starting address for the String Literal "abc" to the pointer s. Whenever you attempt to use sizeof() on a_pointer, you get sizeof(a_pointer) which is typically 8-bytes on x86_64 (or 4-bytes on x86, etc..)
If you take sizeof("abc"); you are taking the size of a character array with size 4 (e.g. {'a', 'b', 'c', '\0'}), because a string literal is an array of char initialized to hold the string "abc" (including the nul-terminating character). Also note, that on virtually all systems, a string literal is created in read-only memory and cannot be modified, it is immutable.
If you want to allocate storage to hold a copy of the string "abc", you must allocate strlen("abc") + 1 characters (the +1 for the nul-terminating character '\0' -- which is simply ASCII 0, see ASCII Table & Description.
Whenever you allocate memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed. So if you allocate for char *st = malloc (len + 1); characters, you do not want to iterate with the pointer st (e.g. no st++). Instead, declare a second pointer, char *p = st; and you are free to iterate with p.
Also, in C, there is no need to cast the return of malloc, it is unnecessary. See: Do I cast the result of malloc?.
If you want to add to an allocation, you use realloc() which will create a new block of memory for you and copy your existing block to it. When using realloc(), you always reallocate using a temporary pointer (e.g. don't st = realloc (st, new_size);) because if when realloc() fails, it returns NULL and if you assign that to your pointer st, you have just lost the original pointer and created a memory leak. Instead, use a temporary pointer, e.g. void *tmp = realloc (st, new_size); then validate realloc() succeeds before assigning st = tmp;
Now, reading between the lines that is where you are going with your example, the following shows how that can be done, keeping track of the amount of memory allocated and the amount of memory used. Then when used == allocated, you reallocate more memory (and remembering to ensure you have +1 bytes available for the nul-terminating character.
A short example would be:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define THISMANY 23
int main (void) {
char *s = "abc", *st, *p; /* string literal and pointer st */
size_t len = strlen(s), /* length of s */
allocated = len + 1, /* number of bytes in new block allocated */
used = 0; /* number of bytes in new block used */
st = malloc (allocated); /* allocate storage for copy of s */
p = st; /* pointer to allocate, preserve st */
if (!st) { /* validate EVERY allocation */
perror ("malloc-st");
return 1;
}
for (int i = 0; s[i]; i++) { /* copy s to new block of memory */
*p++ = s[i]; /* (could use strcpy) */
used++; /* advance counter */
}
*p = 0; /* nul-terminate copy */
for (size_t i = 0; i < THISMANY; i++) { /* loop THISMANY times */
if (used + 1 == allocated) { /* check if realloc needed (remember '\0') */
/* always realloc using temporary pointer */
void *tmp = realloc (st, 2 * allocated); /* realloc 2X current */
if (!tmp) { /* validate EVERY reallocation */
perror ("realloc-st");
break; /* don't exit, original st stil valid */
}
st = tmp; /* assign reallocated block to st */
allocated *= 2; /* update allocated amount */
}
*p++ = 'a' + used++; /* assign new char, increment used */
}
*p = 0; /* nul-terminate */
printf ("result st : %s\n" /* output final string, length, allocated */
"length st : %zu bytes\n"
"final size : %zu bytes\n", st, strlen(st), allocated);
free (st); /* don't forget to free what you have allocated */
}
Example Use/Output
$ ./bin/sizeofs
result st : abcdefghijklmnopqrstuvwxyz
length st : 26 bytes
final size : 32 bytes
Look things over and let me know if this answered your questions, and if not, leave a comment and I'm happy to help further.
If you are still shaky on what a pointer is, and would like more information, here are a few links that provide basic discussions of pointers that may help. Difference between char pp and (char) p? and Pointer to pointer of structs indexing out of bounds(?)... (ignore the titles, the answers discuss pointer basics)
My understanding:
char * c means c is pointing nothing.
When I type "Hello World", c is now pointing the first address of "Hello World".
It should print H and e, but I got "Segmentation fault: 11" error.
Can anyone please enlighten me why and how char * c = NULL; is causing an error?
Thanks in advance!
#include <stdio.h>
int main(void)
{
char * c = NULL;
gets(c);
printf("%c, %c\n", c[0], c[1]);
return 0;
}
gets doesn't allocate memory. Your pointer is pointing to NULL, which cannot be written to, so when gets tries to write the first character there, you seg fault.
The solution is:
Use a stack or global array (char c[1000];) or a pointer to dynamically allocated memory (char *c = malloc(1000);), not a NULL pointer.
Never use gets, which is intrinsically broken/insecure (it can't limit the read to match the size of the available buffer); use fgets instead.
char *c = NULL; declares the pointer c initialized to NULL. It is a pointer to nowhere.
Recall, A pointer is just a variable that holds the address to something else as its value. Where you normally think of a variable holding an immediate values, such as int a = 5;, a pointer would simply hold the address where 5 is stored in memory, e.g. int *b = &a;. Before you can use a pointer to cause data to be stored in memory -- the pointer must hold the address for (e.g. it must point to) the beginning of a valid block of memory that you have access to.
You can either provide that valid block of memory by assigning the address of an array to your pointer (where the pointer points to where the array is stored on the stack), or you can allocate a block of memory (using malloc, calloc or realloc) and assign the beginning address for that block to your pointer. (don't forget to free() what you allocate).
The simplest way is to declare a character array and then assign the address to the first element to your pointer (an array is converted to a pointer to the first element on access, so simply assigning the character array to your pointer is fine). For example with the array buf providing the storage and the pointer p holding the address of the first character in buf, you could do:
#include <stdio.h>
#include <string.h> /* for strcspn & strlen */
#define MAXC 1024 /* if you need a constant, #define one (or more) */
int main (void)
{
char buf[MAXC], /* an array of MAXC chars */
*p = buf; /* a pointer to buf */
if (fgets (p, MAXC, stdin)) { /* read line from stdin */
p[strcspn (p, "\n")] = 0; /* trim \n by overwriting with 0 */
if (strlen (p) > 1) { /* validate at least 2-chars */
printf("%c, %c\n", p[0], p[1]); /* output them */
}
}
return 0;
}
(note: strcspn above simply returns the number of character in your string up to the '\n' character allowing you to simply overwrite the '\n' included by fgets() with '\0' -- which is numerically equivalent to 0)
Example Use/Output
$ ./bin/fgetsmin
Hello
H, e
Look things over and let me know if you have further questions.
I want make array which will be declared dynamically I imagine something like this. I want make program that recognize characters in the word.
char i;
scanf("%c",&i);
char word[]=i;
printf("%c",word[0]);
I also tried something like this:
char i;
scanf(%c,&i);
char *word=i;
printf("%c",word[0]);
I have no clue how to make it work.
Let's just start with the basics. What you are declaring when your write:
char word[]=i;
is an array of characters which will be initialized based on what is to the right of the = sign. In this case to i which is a single character (even though that technically is an invalid initializer). So essentially you are attempting to declare a character array of size 1.
If that were allowed, word would not a character string because it was not (and could not be) null-terminated. It is simply an array of type char and cannot be used as a string. (note char word[]="i"; would work - and be null-terminated)
When you declare word as:
char *word=i;
you have created a pointer to type char that is incorrectly initialized to hold the memory address of i.
(a pointer simply contains, as its value, the address for something else stored in memory, in this case you have set that address to the value of i which likely is in the system reserved range of memory and will probably cause an immediate segmentation fault.
What you probably intended was:
char *word=&i;
Where you store the address of i as the value of word. While this will give you a character pointer to i, it has nothing to do with dynamic allocation beyond involving a pointer.
To properly allocate word dynamically, you do still need to create a pointer named word, but you then need to allocate a block of memory that word will point to. (pointing to the starting address for that block of memory). So to dynamically allocate space for word you would expect to see something like:
char *word = NULL; /* initialization to NULL is good practice */
word = malloc (numbytes * sizeof *word); /* allocate numbytes of storage */
You then have a pointer word whose value is the starting address of the new block of memory of (numbytes x sizeof *word) bytes in size. (since sizeof *word is simply the sizeof (char) its value is 1). So you have created a block of memory numbytes in size.
You have two responsibilities regarding that block of memory (1) you must preserve a pointer to the starting address of that block; so (2) you can free the memory when it is no longer needed. (1) means no word++;, etc.. in your code. If you need to iterate a pointer value, create a pointer, e.g.:
char *p = word;
Then you can use pointer arithmetic on p without effecting the value of word.
You can then fill word any way you like as long as you leave room for a null-terminator at the end (if you are going to use it as a string) and don't attempt to write more than numbytes worth of data to it.
So in your case, if your intent was to dynamically allocate word to hold the character i to be printed as a string, you could easily do:
char *word = NULL;
word = malloc (10 * sizeof *word);
if (!word) { /* always validate each allocation */
fprintf (stderr, "error: virtual memory exhausted.\n");
return 1;
}
if (scanf ("9%s", word))
printf ("word contains '%s'\n", word);
free (word);
Note: that when using scanf ("9%s", word), you will stop reading as soon as the first space is encountered. You may want to use scanf ("9%[^\n]%*c", word) which essentially says %9[^\n] read up to 9 characters (that do NOT include a \n), then %*c read and discard the newline without adding it to the match count returned by scanf. So your test:
if (scanf ("9%s", word))
insures scanf has read at least one character into word as a string (null-terminating word) which on successful read is added to the match count for scanf making the match count = 1. The match count is then returned by scanf insuring that you only print after a successful read.
Note also: the number of character scanf will read is limited to 9 by including a width specifier %9s (or %9[^\n]) in the format string. This insures you cannot write beyond the end of the memory allocated to word while guaranteeing space available to null-terminate the string.
One other nit. If you are expecting a user to enter data, then prompt the user to enter the data, so the user isn't left looking at a blinking cursor on the screen, wondering if the program got hung up, etc.. Putting all this together in a short example.
#include <stdio.h>
#include <stdlib.h>
int main (void) {
char *word = NULL;
word = malloc (10 * sizeof *word);
if (!word) { /* always validate each allocation */
fprintf (stderr, "error: virtual memory exhausted.\n");
return 1;
}
printf ("\nEnter up to 9 characters to store in 'word': ");
if (scanf ("%9[^\n]%*c", word))
printf ("word contains '%s'\n", word);
free (word);
return 0;
}
Use/Output
$ ./bin/dynalloc
Enter up to 9 characters to store in 'word': dog
word contains 'dog'
$ ./bin/dynalloc
Enter up to 9 characters to store in 'word': 1234567890
word contains '123456789'
$ ./bin/dynalloc
Enter up to 9 characters to store in 'word': my dog
word contains 'my dog'
Let me know if you have any questions.
#include<stdio.h>
int main()
{
char *arg[10],*c;
int count=0;
FILE *fp,*fq;
printf("Name of the file:");
scanf("%s",arg[1]);
fp=fopen(arg[1],"w");
printf("\t\t%s",arg[1]);
printf("Input the text into the file\n");
printf("Press Ctrl+d to the stop\n");
while((*c=getchar())!=EOF)
{
fwrite(c,sizeof(char),1,fp);
count++;
}
return 0;
}
Change this line
char *arg[10],*c;
to
char arg[1000],c;
This line
scanf("%s",arg[1]);
to
scanf("%s",arg);
And this line
while((*c=getchar())!=EOF)
to
while((c=getchar())!=EOF)
Explanation:
char *c; is not a character. It's a pointer to a character. It starts out just pointing to a random bit of memory, which will often be filled with random data - whatever was most recently written there.
char c; is a character.
The same thing applies to char *arg[10]. It's an array of ten pointers. They point into random memory, filled with random data.
Note: my change is not best practice. If someone were to type in a filename 1000 characters or more long, you'd write over the end of the arg buffer. Depending on what you're doing, this can be a security bug.
In
char *arg[10];
you define an array of 10 pointers to char but you do not initialize its elements. arg[0], arg[1], ..., arg[9] will all have undefined values.
Then, you try to enter a string into one of those undefined values. Lucky you, you got a segmentation fault. Had you been unlucky, your program could format your hard disk instead.
char *arg[10] ;
arg is array of char pointers. You need to assign them memory locations using malloc before taking input -
scanf("%s",arg[1]); // arg[1] is not assigned to point to any memory location
// and is what causing the segmentation fault.
So do -
arg[1] = malloc( stringLengthExpectedToEnter + 1 ) ; // +1 for termination character
Should do like that with the rest of array elements too (or) simply change char*arg[10] to char arg[10] and make sure to enter only enter 9 characters.
I think you are confusing between a pointer and a normal variable.
int *ptr;
ptr is variable that can hold the address of an integer variable. Memory is allocated to for ptr variable to hold an integer address. That's it. ptr is in an uninitalized state and is pointing no where (or) might be pointing to garbage. Dereferencing an uninitialized pointer's behavior is undefined and you are lucky enough if it gives a segmentation-fault.
Now, you need to assign it a valid memory location using malloc.
ptr = malloc( sizeof(int) ) ; // Allocates number of bytes required to hold an
// integer and returns it's address.
So, ptr is now pointing to memory location acquired from free store that can hold an integer. Such acquired locations from free stored must be freed using free, else you have classical problem of memory leak. It is good practice to initialize pointer to NULL while declaration.
int *ptr = NULL ;
Hope it helps !
scanf("%d", ptr) ; // Notice that & is not required before ptr. Because ptr
// content is address itself.
A normal variable story is entirely different. When declared -
int var ;
Memory is allocated to var to hold an integer. So, you can directly assign it an integer.
#include<stdio.h>
int main()
{
char arg[10],c;
int count=0;
FILE *fp;
printf("Name of the file:");
scanf("%s",arg);
fp=fopen(arg,"w");
printf("\t\t%s",arg);
printf("Input the text into the file\n");
printf("Press Ctrl+d to the stop\n");
while((c=getchar())!=EOF)
{
fwrite(&c,sizeof(char),1,fp);
count++;
}
if(fp != NULL){
fclose(fp);
fp = NULL;
}
return 0;
}
gcc 4.4.4 c89
I understand pointers ok. However, I am stepping up to pointer arrays and pointers to pointers.
I have been messing around with this code snippet and have left comments of what I think I understand.
Many thanks for any advice if my comments are correct with the line of code?
void increment_ptr()
{
/* Static char array */
char src[] = "rabbit";
/* pointer to array of pointers to char's - create 6 pointers in this array */
char *dest[sizeof(src)];
size_t i = 0;
/* pointer to a char */
char* chr_ptr = NULL;
/* pointer to pointer that points to a char */
char** ptr_ptr = NULL;
/* chr_ptr pointer now points to the memory location where 'rabbit' is stored. */
chr_ptr = src;
/* ptr_ptr points to the first memory address of the pointer array of where dest is stored */
ptr_ptr = dest;
/* Deference chr_ptr and keep going until nul is reached 'rabbit\0' */
while(*chr_ptr != '\0')
/* deference ptr_ptr and assign the address of each letter to the momory location where
ptr_ptr is currently pointing to. */
*ptr_ptr++ = chr_ptr++;
/* reset the ptr_ptr to point to the first memory location 'rabbit' */
ptr_ptr = dest;
/* Keep going until NULL is found - However, my program never finds it, ends in UB */
while(ptr_ptr != NULL) {
/* Dereference what the pointer to pointer is pointing at the memory lcoation */
printf("[ %s ]\n", *ptr_ptr++);
}
}
Comments below each part (bits I haven't mentioned are correct):
/* Static char array */
char src[] = "rabbit";
This array is not static - it has auto storage duration.
/* pointer to array of pointers to char's - create 6 pointers in this array */
char *dest[sizeof(src)];
This is an array of pointers to char, not a pointer to an array. The length of the array is 7, because the sizeof(src) is 7 (it includes the nul string terminator).
/* chr_ptr pointer now points to the memory location where 'rabbit' is stored. */
chr_ptr = src;
More precisely, it points at the first character in src, which is the 'r' in "rabbit".
/* ptr_ptr points to the first memory address of the pointer array of where dest is stored */
ptr_ptr = dest;
It points at the first pointer in the dest array.
/* Keep going until NULL is found - However, my program never finds it, ends in UB */
while(ptr_ptr != NULL) {
Correct - because you never initialised dest. You could change the declaration of dest to this:
char *dest[sizeof(src)] = { 0 };
...and it will work.
I would suggest that you read Section 6 of the online C-FAQ: 6. Arrays and Pointers
The error is when you assign dest to ptr_ptr, which is actually an uninitialized array of pointers to chars, going through it withing the while loop will fail.
/* reset the ptr_ptr to point to the first memory location 'rabbit' */
ptr_ptr = dest;
/* Keep going until NULL is found - However, my program never finds it, ends in UB */
while(ptr_ptr != NULL) {
/* Dereference what the pointer to pointer is pointing at the memory lcoation */
printf("[ %s ]\n", *ptr_ptr++);
}