Dereferencing a double pointer and using index operator - c

I am passing a double pointer of type char ** to a function. Inside that function, I need to dereference the pointer and then index through the character array.
Unfortunately, I am getting a core dump when I try to assign a capital letter back into the array.
I need help on how to do this. (This is not homework, just a personal project.)
void buffer(char **ppline);
int main()
{
char *line="The redcoats are coming!";
buffer(&line);
printf("\nline = %s\n",line);
return(0);
}
void buffer (char **ppline)
{
int i=0;
char a;
for (i=0; i < strlen(*ppline); i++)
{
a = toupper( (*ppline)[i] ); /* THIS LINE CAUSES THE CORE DUMP */
((*ppline)[i]) = a;
}
return;
}

A string literal in "" is constant. You cannot modify it as you're doing, as that is undefined behavior. Try this, which allocates storage and copies the string literal into it:
void buffer(char **ppline);
int main()
{
char line[] = "The redcoats are coming!";
buffer(&line);
printf("\nline = %s\n",line);
return(0);
}
void buffer (char **ppline)
{
int i=0;
char a;
for (i=0; i < strlen(*ppline); i++)
{
a = toupper( (*ppline)[i] ); /* THIS LINE CAUSES THE CORE DUMP */
((*ppline)[i]) = a;
}
return;
}

Stack, heap, datasegment(and BSS) and text segement are the four segments of process memory. All the local variables defined will be in stack. Dynmically allocated memory using malloc and calloc will be in heap. All the global and static variables will be in data segment. Text segment will have the assembly code of the program and some constants.
In these 4 segements, text segment is the READ ONLY segment and in the all the other three is for READ and WRITE.
char []a="The redcoats are coming!"; - This statemnt will allocate memory for 25 bytes in stack(because local variable) and it will keep all the 24 characters plus NULL character (\0) at the end.
char *p="The redcoats are coming!"; - This statement will allocate memory for 4 bytes(if it is 32 bit machine) in stack(because this is also a local variable) and it will hold the pointer of the constant string which value is "The redcoats are coming!". This byte of constant string will be in text segment. This is a constant value. Pointer variable p just points to that string.
Now a[0] (index can be 0 to 24) means, it will access first character of that string which is in stack. So we can do write also at this position. a[0] = 'x' This operation is allowed because we have READ WRITE access in stack.
But p[0] = 'x' will leads to crash, because we have only READ access to text segement. Segmentation fault will happen if we do any write on text segment.
But you can change the value of variable p, because its local variable in stack. like below
char *p = "string";
printf("%s", p);
p = "start";
printf("%s", p);
This is allowed. Here we are changing the address stored in the pointer variable p to address of the string start(again start is also a read only data in text segement). If you want to modify values present in *p means go for dynamically allocated memory.
char *p = NULL;
p = malloc(sizeof(char)*7);
strcpy(p, "string");
Now p[0] = 'x' operation is allowed, because now we are writing in heap.

Related

Why char * c = NULL; causes an error in the following code?

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.

How to set a char 'a' to a char pointer array?

I'm trying to figure out how to use pointers.
I'm confused on how to insert an individual char to the char *line2[80]
Is this even possible to do this without referencing the memory location of another pointer?
My thought process is that at *line2[0] = 'a' the character 'a' will be at index 0 of the array.
How is this different from line[0] = 'a'
#include <stdio.h>
void returnValue(void);
int main(void){
returnValue();
}
void returnValue(){
char line[80];
line[0] = 'a';
line[1] = '\0';
printf("%s",line);
char* line2[80];
*line2[0] = 'a';
*line2[1] = '\0';
printf("%s",*line2); //program crashes
}
When you allocate
char* line2[80];
You are allocating an array of 80 character pointers.
When you use
*line2[0] = 'a';
You are referencing undefined behaviour. This is because you are allocating the pointer line2[0], but the pointer is not initialized and may not be pointing to any valid location in memory.
You need to initialize the pointer to some valid location in memory for this to work. The typical way to do this would be to use malloc
line2[0] = malloc(10); // Here 10 is the maximum size of the string you want to store
*line2[0] = 'a';
*(line2[0]+1) = '\0';
printf("%s",*line2);
What you are doing in the above program is allocating a 2D array of C strings. line2[0] is the 1st string. Likewise, you can have 79 more strings allocated.
you must have already read, a pointer is a special variable in c which stores address of another variable of same datatype.
for eg:-
char a_character_var = 'M';
char * a_character_pointer = &a_character_var; //here `*` signifies `a_character_pointer` is a `pointer` to `char datatype` i.e. it can store an address of a `char`acter variable
likewise in your example
char* line2[80]; is an array of 80 char pointer
usage
line2[0] = &line[0];
and you may access it by writing *line2[0] which will yield a as output

Converting char * to uppercase segfaults

I have a simple program where I have a string I've written in externally (in the case of this snippit, it's user created). And I'm trying to capitalize certain parts of it.
I first strtoked it by a delimiter, and attempted to capitalize it using the toupper function, however I seem to be getting segfaults doing it. Running valgrind provides no error, except simply states that:
Process terminating with default action of signal 11 (SIGSEGV)
==10180== Bad permissions for mapped region at address 0x4007B9
The code:
int main(void) {
char * test;
char * f;
char * s;
char * p;
test = "first:second:third:fourth:";
f = strtok(test,":");
for(p = f; *p; *p = toupper(*p), p++); //segfaults
printf("f is %s \n",f); //this should print "FIRST" as it should be capitalized
return 0;
}
You can't use strtok() on a string literal because it modifies it's argument, and you can't modify a string literal.
Nor can you modify it in this loop
for (p = f; *p; *p = toupper(*p), p++); //segfaults
You need an array or a dynamically allocated block of memory, both of which are writeable, with the array you can initialize using a string literal like this
char array[] = "This is a string literal, you are not allowed to modify it";
/* Now the arest of the code could work but ... */
You also need to check the return value of strtok() which is NULL when it doesn't find what you ask to find.
Using malloc() you can do this too
cosnt char *string_literal = "This is a sample string";
size_t length = strlen(string_literal);
char *buffer = malloc(length + 1);
if (buffer == NULL)
return -1; // Allocation failure.
memcpy(buffer, string_literal, length + 1);
// ^ copy the null terminator too
// Process your newly allocated copy here and,
free(buffer);
NOTE: About your original code with
f = s = p = test = malloc(sizeof(char * ) * 10);
malloc() is not used as a general initialization function, it's used to get a pointer to memory that you can use in the program, you can read/write from/to it. When you ask for memory with malloc() you ask for a specific (usually exact) ammount of bytes to be used in your program.
The returned pointer is then usable if it's not NULL, in case there is an error or the system has ran out of memory it will return NULL.
Your code has a major issue since all the pointers f, s, p and test point to the same memory address and also because you allocated an arbitrary size which might or not be the one you want/need.
When you free(f) and then go on and free(s), you are freeing the same pointer twice and you actually was doing it more than that. Calling free() twice on the same poitner invokes undefined behavior.

How does strcpy() copy a string to an array when you can't change the address of an array?

So basically strcpy assigns the address of the 2nd argument to the 1st, but how does it do it with an array as the first argument? like in my program, i tried changing the address of the array but unfortunately it wont compile. So I had to resort to making a character pointer variable to assign the return value of capitalize. Is there something I'm misunderstanding?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef char string[20];
char *Capitalize(char *str)
{
int i;
char *temp;
temp = malloc(sizeof(char)*(int)(strlen(str)+1));
for(i = 0;i < strlen(str);i++)
{
if(*(str+i) >= 'a' && *(str+i)<= 'z')
*(temp+i) = *(str+i) - 32;
else
*(temp+i) = *(str+i);
}
*(temp+i) = '\0';
return temp;
}
int main(void)
{
string word;
printf("Enter word to capitalize: ");
scanf("%19s",word);
word = Capitalize(word);
printf("%s",word);
return 0;
}
strcpy() makes a copy, just like the name implies. it's perfectly legal to copy a string in to an array.
When you make an initialization of an array such as:
char myarr[] = "hello";
You're actually copying the characters into the array.
You seem to be confusing arrays with pointers (see here for some reason you can't treat them the same)
In C, qualifying an array by name without an indexer, is equivalent to specifying a pointer to the memory address of the first element in the array, that is why you can pass as a parameter an array to functions like strcpy.
char * strcpy ( char * destination, const char * source );
strcpy will copy whatever series of characters are found, starting at memory address specified by source, to the memory address specified by destination, until a null character (0) is found (this null character is also copied to the destination buffer).
The address values specified in the parameters are not modified, they just specify from where in memory to copy and where to. It is important that destination is pointing to a memory buffer (can be a char array or a block of memory requested via malloc) with enough capacity for the copied string to fit, otherwise a buffer underrun will occur (you will write characters past the end of your buffer) and your program might crash or behave in a weird way.
Hope I have been clear and not confused you more with my explanation ;)
The thing you seem to be missing is that in c/c++ strings ARE arrays, in most practical respects declaring
char c[] = "hello";
and
char* c = "hello";
is the same thing, all strcpy does is copy the characters into the destination memory, whether that memory is allocated as an array (presumably on the stack) or pointer (presumably on the heap);it does not make a difference.

segmentation fault during execution

#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;
}

Resources