Dereferencing string pointers in C - c

I am new to C and I would like to know the difference between the below two snippet codes.When I try executing first one it works fine,but when I run the second one it gives me segmentation fault.Whats the reason for this behavior?
printf("%c\n",*strptr++);
printf("%c\n",*(strptr+i));
Here is the below code.
#include<stdio.h>
int main(void)
{
char str[100]="My name is Vutukuri";
int i=0;
char *strptr;
strptr=str;
while(*strptr != '\0')
{
printf("%c\n",*strptr++);
//printf("%c\n",*(strptr+i));
//i++;
}
return 0;
}

Entirely different.
The first snippet prints the character at strptr and then increments strptr by one.
The second snippet prints the character at strptr + i.

Apparently, the address strptr refers to an allocated place in memory, while strptr + i points to an unallocated place. If you allocate a string as
char s[LENGTH];
or
char* s = (char*)malloc(LENGTH * sizeof(char));
then you can only use the characters from s[0] to s[LENGTH - 1] (and the string itself can only be LENGTH - 1 long, so there is place for a null terminator). In your case, the pointer strptr + i is probably not in the range s...s + LENGTH - 1.

Maybe you want to replace i with 1.
++ operator first uses the initial value, and then it increments it.
+operator calculates the new value and then uses it.

Related

Can't understand the difference between declaring a pointer char *str as str/&str?Whats the difference and what does it do?

I will say honestly, this isn't my code. It's my brother's who's studying with me but he's a ahead of me.
Please notice char *str and char *resultString in the function char *replaceWord().
/*Suppose you have a template letter.txt. You have to fill in values to a template. Letter.txt looks something like this:
Thanks {{name}} for purchasing {{item}} from our outlet {{outlet}}. Please visit our outlet {{outlet}} for any kind of problems. We plan to serve you again soon.
You have to write a program that will automatically fill the template.For this, read this file and replace these values:
{{name}} - Harry
{{item}} - Table Fan
{{outlet}} - Ram Laxmi fan outlet
Use file functions in c to accomplish the same.*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char * replaceWord(const char * str, const char * oldWord, const char * newWord)
{
char * resultString;
int i, count = 0;
int newWordLength = strlen(newWord);
int oldWordLength = strlen(oldWord);
for (i = 0; str[i] != '\0'; i++)
{
if (strstr(&str[i], oldWord) == &str[i])
{
count++;
//Jumping over the word and continuing
i = i + oldWordLength - 1;
}
}
//dynamically allocation memory to resultString since it can be big or samll depending on the size of the newWord.
/*i = old string length , count = no. of times the word appeared in the string,
newWordLength-oldWordLength=difference between the new word and the old word
+1 for the null character '\0'
Basically we are saying that add the size required for the newWord to the strings length i.e i;
*/
resultString = (char *)malloc(i + count * (newWordLength - oldWordLength) + 1);
i = 0; //refreshing the i for the while loop
while (*str)
{
if (strstr(str, oldWord) == str)
{
strcpy(&resultString[i], newWord);
i += newWordLength;
str += oldWordLength;
}
else
{
resultString[i] = *str;
i+=1;
str+=1;
}
}
resultString[i] = '\0';
return resultString;
}
int main()
{
FILE *ptr = NULL;
FILE *ptr2 = NULL;
ptr = fopen("letter.txt", "r"); //where the template is stored
ptr2 = fopen("newLetter.txt", "w"); //where the new bill will be stored.
char str[200];
fgets(str, 200, ptr); //store the bill template in the str variable.
printf("The original bill template is : %s\n", str);
//Calling the replacing fucntion
char *newStr = str; //newStr will store the new bill i.e generated
newStr = replaceWord(str, "{{name}}", "Mary");
newStr = replaceWord(newStr, "{{item}}", "Waffle Machine");
newStr = replaceWord(newStr, "{{outlet}}", "Belgium Waffle");
printf("\nThe bill generated is:\n%s", newStr);
fprintf(ptr2, "%s", newStr);
fclose(ptr);
fclose(ptr2);
return 0;
}
Can someone explain why the pointer *str and *resultString are expressed different ways in the program and what are they doing? Sometimes it's *str, &str or str[i].
Please explain.
I know that a pointer is used to keep the address of the other variables but this code is still a mystery to me.
Also why was the function a pointer?
NOTE:"He said that's how it works" when I asked how.
Please help!! I can't focus on other things.
If you can't explain ;a link of explanation would be fine as well.
Sometimes it's *str, &str or str[i]
Those are operators.
*str
str is a poitner to a char, and having a * over it dereferences it. Meaning it fetches the value from the memory that it is pointing to. A pointer may not always point to a variable though, it can be any arbitrary memory address. But dereferencing memory that is not yours will result in Segmentation fault which is the my most beloved error that occurs almost everytime when processing arrays.
str[i]
This is the same as *(str + i). Meaning it increments the memory address by i * sizeof(<datatype of what str points to>). Then it fetches the value from that incremented address. This is used for getting elements of an array.
&str
This just given the address of the variable str, which is a pointer. So, it returns a pointer to a pointer(ie. str). A pointer to a pointer can exist.
The function is not a pointer. Instead, it returns a pointer which is *resultString. It is so that a string can be returned. The string had been initialized in this line:
resultString = (char *)malloc(i + count * (newWordLength - oldWordLength) + 1);
The comment explaining this is not complete.
//dynamically allocation memory to resultString since it can be big or samll depending on the size of the newWord.
/*i = old string length , count = no. of times the word appeared in the string,
newWordLength-oldWordLength=difference between the new word and the old word
+1 for the null character '\0'
Basically we are saying that add the size required for the newWord to the strings length i.e i;
*/
It also misses one key reason why malloc is being used instead of normal allocation. malloc allocates your variables on the heap which is shared among all functions and threads. While normal initialization would allocate it on the stack which is popped off when the function ends. So, no use after the function with the stack, so it should be used on the heap. And it is also for dynamic allocation.

The following C code outputs a segmentation fault error which I can hardly understand why

#include <stdio.h>
void append(char* s, char n);
void splitstr(char* string);
int main()
{
splitstr("COMPUTE 1-1");
printf("\n");
splitstr("COMPUTE 1+1");
printf("\n");
splitstr("COMPUTE 1*1");
return 0;
}
void append(char* s, char ch) {
while(*s != '\0'){
s = s + 1;
}
*s = ch;
s = s + 1;
*s = '\0';
}
void splitstr(char* string){
int count = 1;
char* expression = "";
while(*string != '\0'){
if(count > 8){
append(expression, *string);
string = string + 1;
count = count + 1;
}else{
string = string + 1;
count = count + 1;
}
}
printf("%s",expression);
}
Example Input and Output:
Input: COMPUTE 1+1
Output: 1+1
Input: COMPUTE 2-6
Output: 2-6
Originally, this code does not include stdio.h (I am doing this for testing on an online C compiler) because I am building an OS from scratch so I need to write all the functions by myself. I think the problem might be in the append function but I cannot find it.
instead of
char* expression = "";
do
char[MAX_expression_length+1] expression;
or use realloc in the append function
I think this line is the culprit:
append(expression, *string);
Notice how expression is declared:
char* expression = "";
In other words, expression consists of one byte, a single \0. Right away, we can see that append() won't work like you want it to--the while loop will never run, because *s is already \0.
But beyond that, the segfault likely happens at the bottom of append(). After the while loop, you unconditionally increment s and then write to the location it now points to. The problem is that this is a location that has never been allocated (since s is a reference to splitstr()'s expression, which is a single byte long). Furthermore, because expression is declared as a string constant, depending on your platform it may be placed in an area of memory marked read-only. Consequently, this is an attempt to write into memory that may not actually belong to the process and may also not be writable, raising the fault.
expression points to a string literal, and trying to modify a string literal leads to undefined behavior.
You need to define expression as an array of char large enough to store your final result:
char expression[strlen(string)+1]; // VLA
Since your result isn’t going to be any longer than the source string, this should be sufficient (provided your implementation supports VLAs).

Manipulating and accessing char *s pointer variable (string) using another pointer variable char *c - C

I've hit a roadblock, when trying to manipulate strings when "storing" them as pointer variables.
// Sample code to input a string till line break is encountered, later re-allocating to save space
char *s = malloc(1024 * sizeof(char));
scanf("%[^\n]", s);
s = realloc(s, strlen(s) + 1);
// Code to replace whitespaces with newlines
for (char *c = s; *c != '\0'; c++) {
if (*c == ' ') {
*c = '\n';
}
}
printf("%s", s);
I want an explanation of char *c = s in the above code snippet, because when I tried to use the same concept to iterate over the string characters in another example (below) I was greeted with Segmentation fault runtime error.
I want to find the frequency of digits (0 to 9) from a string entered by the user:
int count[10];
char *s = malloc(1024 * sizeof(char));
scanf("%[^\n]", &s);
s = realloc(s, strlen(s) + 1);
for(char *c = s; *c != '\0'; c++) { // Shows Segementation fault here
if(*c >= '0' && *c <= '9') {
count[*c - '0'] += 1; // I am still trying to work this
}
}
In scanf you are using &s instead of s.
explanation of char *c = s:
in this statement, the pointer c is set to the same address as the pointer s for the first iteration of the for-loop. That means, c and s point to the same memory location. Then, for each further iteration of the for-loop, c is incremented (c++) and the for loop is executed as long as the dereferenced memory location (the content at the memory location) is not the null character.
Now for the segmentation fault, as you didn't post the non-working code, I can only guess. One guess could be that there is no null character inside the allocated memory, so the for loop is not stopping soon enough and increments the c pointer to an address higher than allocated with malloc. By dereferencing it you access a memory location outside the allocated memory. This can produce a segmentation fault.
Edit:
ah, now I see you added the non-working code. Yes, Akshay's answer is right and the segmentation fault could already happen there, as you don't scanf to s but to the memory location where the pointer variable is saved. The array pointed by s is still uninitialized (unknown values) but you search for the first occurence of the null character with strlen. Now, realloc may fail and thus return NULL and then you would set your c pointer to NULL. That would also produce a segmentation fault.

How to edit values of a char* string in C?

I just started learning C and I'm quite unsure of how to "correctly" access and edit values of a character pointer.
For example:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char* text = malloc(20);
char* othertext = "Teststring";
do
{
*text++ = *othertext++;
} while (*othertext != '\0');
printf("%s\n", text + 3);
free(text);
return 0;
}
Firstly, why does the do-while function not work? The content of "othertext" doesn't get copied to the "text" pointer. Furthermore, the program crashes when free(text) is being executed!
We know that this code works if we add a second pointer:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char* text = malloc(20);
char* othertext = "Teststring";
char *ptr1 = text;
char *ptr2 = othertext;
do
{
*ptr1++ = *ptr2++;
} while (*ptr2 != '\0');
printf("%s\n", text + 3);
free(text);
return 0;
}
But both pointers have basically the same address! They have the same values in the debugger, so how does a second pointer make any difference?
As a final note: We are not allowed to use string.h. And we do know there's a subtle difference between arrays and pointers. But we need to specifically understand how char* works!
You should pass to free() the pointer returned by malloc() (the same address). You are passing the incremented pointer i.e. the text pointer now doesn't have the address of the pointer returned by malloc() instead it's an the address of the last element of text, use another pointer to copy the data, or better an index
size_t i;
for (i = 0 ; othertext[i] != '\0' ; ++i)
text[i] = othertext[i];
text[i] = '\0';
You say
But both pointers have basically the same address!
This is not true, try this
printf("%p -- %p\n", (void *) text, (void *) ptr1);
You modify the value of the text pointer in your loop, such that at the end it's not pointing to the beginning of the memory region you allocated; that's (part of) why you don't see the text, and why the free crashes.
You need to preserve that original pointer value (which you do in your second snippet).
You are actually changing the address that text is pointing too.
Consider a very simple memory in which text points to address 5 and othertext points to address 42 on which the T of TestString has been placed.
You now copy the character found at address 42 to address 5, so that address 5 also contains a T. However, you now increment the address that text is pointing too. In other words, text now points at address 6. You also increment othertext which now points to address 43.
In the next round you copy the e found at address 43 to address 6 and increment both again. This is all fine.
However after you are done copying text will point to 5 + 10 = 15. On address 15 however you can not print anything, nor can you remove what is there.
In your second piece of code there are no problems because text keeps pointing to address 5.
do this printf inside the loop after the assignment line. I think you will see why it's not working ;)
printf("%s\n", text);

Deleting an element in the middle of array?

I was trying to get an element deleted from the middle of array and then shiffting the whole content, and I had a few difficulties because my test array wasn't "right". I fixed the problem by filling the array with a string using strcpy. The commented part above strcpy is the method I used before(which didn't work). Could somebody explain me maybe why isn't it working?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char *array;
int i=5;
array = (char*)calloc(1024, sizeof(char));
if(array == NULL){
printf("Out of memory\n");
return 0;
}
//array = "Just some test string";
strcpy(array, "Just some test string");
printf("%s\n", array);
memmove(array+i+1, array+i, strlen(array)-i);
array[i] = ',';
printf("%s\n", array);
memmove(array+i, array+i+1, strlen(array)-i);
printf("%s\n", array);
free(array);
return 0;
}
The printf is normally working on the commented part, but the memmove() makes my programm crash!
If you have this:
array = "Just some test string";
then
1) You have memory leak due to overwriting the calloc'ed pointer.
2) You are attempting to modify a string literal. That's probably why it crashes. Modifying a string literal is undefined behaviour. They are typically stored in read-only memory. Since strcpy() makes a copy of the string literal, it works as intended and this method fails.
In these statements
memmove(array+i+1, array+i, strlen(array)-i);
array[i] = ',';
there is an attempt to insert character ',' at the position 5 because variable i was initialized with 5.
So the part of the string including the terminating zero has to be shifted right starting with this position. The length of the part is
strlen( array ) - i + 1
because the terminating zero is also must be moved.
So these statements will look like
memmove( array + i + 1, array + i, strlen( array ) - i + 1 );
array[i] = ',';
Then in these statements
memmove( array + i, array + i + 1, strlen( array ) - i );
This statement is correct. Expression strlen( array ) - i is calculated like
( strlen( array ) + 1 ) - ( i + 1 )
As for this statement
array = "Just some test string";
then pointer array points to a string literal and though string literals in C have types of non-constant character arrays nevertheless they are immutable.
Any attempt to modify a string literal results in undefined behaviour of the program.
Also if before this statement you also initialized this pointer with the result of a call to calloc then there will be a memory leak because the pointer is reassigned and the address of the allocated memory is lost.
I tried to do something like this.
I solved it by having:
*(array+strlen(string)+1)=0;
Null terminating the string, but if the subsequent printf() is working correctly this won't help.
Otherwise see:
http://www.java-samples.com/showtutorial.php?tutorialid=591

Resources