Why is my pointer disappearing? - c

I have a class that is meant to return a char** by splitting one char* into sentences. I can allocate the memory and give it values at a certain point, but by the time I try to return it, it's completely missing.
char **makeSentences(char *chapter, int *nSentences){
int num = *nSentences;
char* chap = chapter;
char **sentences;
sentences = (char**) malloc(sizeof(char*) * num);
int stops[num + 1];
stops[0] = 0;
int counter = 0;
int stop = 1;
while (chap[counter] != '\0'){
if (chap[counter] == '.'){
stops[stop] = counter + 1;
printf("Place: %d\nStop Number: %d\n\n", counter, stop);
stop++;
}
counter++;
}
for (int i = 0; i < num; i++){
int length = stops[i+1] - stops[i];
char characters[length+1];
memcpy(characters, &chap[stops[i]], length);
characters[length] = '\0';
char *sentence = characters;
sentences[i] = sentence;
printf("%s\n",sentence);
printf("%s\n", sentences[i]);
}
char* testChar = sentences[0];
printf("%s\n", sentences[0]);
printf("%s]n", testChar);
return sentences;
}
The last two printing lines don't print anything but a newline, while the exact same lines (in the for loop) print as expected. What is going on here?

The problem is these three lines:
char characters[length+1];
char *sentence = characters;
sentences[i] = sentence;
Here you save a pointer to a local variable. That variable characters will go out of scope every iteration of the loop, leaving you with an "array" of stray pointers.
While not standard in C, almost all systems have a strdup function whichg duplicates a string by calling malloc and strcpy. I suggest you use it (or implement your own).

Related

Reversing a string in C without the output being null

I am trying to reverse a string (character array) using the following code, but when I attempt to print the string, the value of null. This is a homework assignment, but I am trying to learn so any help would be appreciated.
void input_reverse_string(const char* inputStr, char* reverseStr)
{
int i = 0;
int length = 0;
for (; *(inputStr++) != '\0'; i++)
{
length++;
}
while (*inputStr)
{
*reverseStr = *inputStr;
inputStr++;
reverseStr++;
}
const char* chr_ptr = &inputStr[length - 1];
printf("I see a %s\n", *chr_ptr);
*reverseStr = '\0';
printf("%d", length);
/* return reverseStr; */
}
Several things are out of order:
That's a strange way of computing the length of a string. You are using an index variable that you don't need, and incrementing 3 things at the same time, it's unneeded to say the least.
After calculating the length, and incrementing the inputStr pointer up to its end, you don't reset the pointer, so it still points to the end of the string (actually, one after the end!).
Inside the while you are advancing both pointers (inputStr and reverseStr) in the same direction, which can't possibly be right if you want to reverse the string.
The correct way to do this would be:
Compute the length of the string. Either use strlen() or do it by hand, but you really only need to increment one variable to do this. You can avoid incrementing inputStr, just use a temporary pointer.
Start from inputStr + length and walk backwards. Either use a pointer and do -- or just index the string).
Here's a working example:
void reverse_string(const char* inputStr, char* reverseStr) {
unsigned len = 0;
int i;
while (inputStr[len])
len++;
for (i = len - 1; i >= 0; i--) {
reverseStr[len - i - 1] = inputStr[i];
}
reverseStr[len] = '\0';
}
int main(void) {
char a[6] = "hello";
char b[6];
reverse_string(a, b);
puts(b);
return 0;
}
Output:
olleh

Function to reverse a two-dimensional set of strings in C isn't reversing more than the first and last characters

this is my first post in Stack Overflow. If I am missing anything, please let me know and I will try to add more information.
The function below is only supposed to use pointer operations and not array operations, as part of an assignment.
I have this function in C that is part of a larger program:
void reverseString(char strings[NUM_STRINGS][STRING_LENGTH])
{
int i, j;
char *ptr; //Declare pointer variable.
for (i = 0; i < NUM_STRINGS; i++)
{
ptr = strings[i];
do { //Here, we ignore the null terminators in the char array.
ptr++;
} while (*ptr != '\0');
ptr--; //Iterate the pointer variable once downward.
j = i;
while (strings[j] < ptr) //While loop for reversing the string
{
//printf("ptr: %d\n", ptr);
//printf("strings[j]: %d\n", strings[j]);
char temp = *strings[j];
*strings[j++] = *ptr;
*ptr-- = temp;
}
}
}
What it is supposed to do is accept a 2D char array with 4 strings and with each string holding up to 32 bytes of text. Then, it reverses each string in-place in the array. For example, if I input the four strings:
Hello
World
Good
morning
It is supposed to then return:
olleH
dlroW
dooG
gninrom
However, what ends up happening is that only the first and last characters of each string are reversed. For example:
oellH
dorlW
dooG
gorninm
I have tried different solutions such as using i instead of j in the while loop or using prefix ++ instead of suffix, but nothing has worked yet. Any pointers as to what I should be looking for?
Thank you.
The solution is below. As described in my comment below, I added a secondary pointer instead of using strings[j] in the loop. The pointer now references to the beginning of the string instead of the entire array of strings.
void reverseString(char strings[NUM_STRINGS][STRING_LENGTH])
{
int i, j;
char *ptr; //Declare pointer variable.
char *ptr2;
for (i = 0; i < NUM_STRINGS; i++)
{
ptr = strings[i];
ptr2 = strings[i];
do { //Here, we ignore the null terminators in the char array.
ptr++;
} while (*ptr != '\0');
ptr--; //Iterate the pointer variable once downward.
j = i;
while (ptr2 < ptr) //While loop for reversing the string
{
char temp = *ptr2;
*ptr2++ = *ptr;
*ptr-- = temp;
}
}
}

A simple C exercise going wrong: Trying to return a pointer to an array of two strings

"Return a pointer to an array of two strings. The first is the characters
of string s that are at even indices and the second is the characters from
s that are at odd indices"
char **parity_strings(const char *s) {
char** parity = malloc(sizeof(char*) * 2);
char even_strings[] = "";
char odd_strings[] = "";
int x = 0;
int y = 0;
for (int i = 0; i < strlen(s); i++) {
if ((i % 2) == 0) {
even_strings[x] = s[i];
x++;
}
else {
odd_strings[y] = s[i];
y++;
}
}
parity[0] = even_strings;
parity[1] = odd_strings;
return parity;
}
int main(int argc, char **argv) {
char **r = parity_strings(argv[1]);
printf("%s %s %s", r[0], r[1], argv[1]);
return 0;
}
My logic makes sense but the output is always incorrect. For example, with input ababab I get back ababab while the expected output is aaa bbb ababab. What did I do wrong?
The string named even_strings is a local variable, so its memory will be freed after your function returns, so it is not valid to try to return a pointer to it to the caller.
Try changing this line:
char even_strings[] = "";
to something like this:
char * even_strings = malloc(some_size);
The same goes for your odd_strings string.
Also, be sure to pick a good value for some_size so that your program allocates enough memory for each string so that it can hold all the data you are writing to it.
even_strings and odd_strings are arrays of size 1 each. Your code writes out of bounds (even_strings[x] = s[i], odd_strings[y] = s[i]). Furthermore, they're local variables that cease to exist once parity_strings returns, so the returned pointers are garbage.

Want to take the amount of data given by a different string's length

I used 'strlen' to find the length of a string, call it string a. I then did some other things to create a binary string. The binary strings value is longer than string a. I want to return the binary string as long as string a. How would I do that?
Let me try to code it out to maybe help clarify:
int main(int argc, char** argv)
{
int i, j, k, l, prefix_length, sum;
char *s, *dot, *binary_string, *ret_val, *temp_string;
char buf[] = "10.29.246.49/32";
s = strtok(buf, "/");
prefix_length = strlen(s);
for(i = 4; i > 0; i--){
dot = strtok(s, ".");
while (dot != NULL){
j = atoi(dot);
sum = sum + j;
s = strtok(NULL, ".");
}
*binary_string = dec_to_bin(sum);
}
strcpy(temp_string, "0");
for(l = prefix_length - strlen(binary_string); i > 0; i--){
strcat(temp_string, binary_string);
strcpy(binary_string, temp_string);
strcpy(tempstring, "0");
}
ret_val = binary_string;
return 0;
}
Also, can you look at my dec_to_bin and tell me if I'm calling it right and what have you:
char dec_to_bin(int decimal)
{
char *ret;
int d = decimal, i;
for (i = 128; i >= 1; i = i/2){
if(d / i){
ret += '1';
d -= i;
}
else
ret += '0';
}
return *ret;
}
Your dec_to_bin is trying to convert a number to a string of '1's and '0's, but is only returning the first char value
You are defining ret as a char * pointer, but you are using it like a std::string which it is not. It is a pointer to memory, and you have to provide it with some memory to point to. As it is you are overwriting random memory, although in debug mode ret probably is initialised to 0, so you will just get a memory exception.
You could allocate the memory with malloc, but this will lead to a world of pain as the way you call the function will simply result in memory leaks.
If you have to use char* pointers and not std::string then I would suggest passing it a buffer to write the string to. You know the string will always be 8 characters long plus the null terminator
char buffer[9];
dec_to_bin(sum, buffer);
ret += '1' is not doing what you think it does. It is adding a char value to a char* pointer which is totally different. You need to store the character at the location pointed to by ret, and then move ret to point to the next location
*ret = '1';
ret = ret + 1;
or
*ret++ = '1';
When this finishes ret will point to the end of the string, so you can't return that. There is not much benefit from returning a value you passed to the routine, but if you must then you need to save it
char* dec_to_bin(int decimal, char *buffer)
{
char *ret = buffer;
int d = decimal, i;
for (i = 128; i >= 1; i = i/2){
if(d / i){
*ret++ = '1';
d -= i;
}
else
*ret++ = '0';
}
return buffer;
}
You should run this program in a debugger, because that will teach you a lot about what is actually going on in your code
If binary_string was a std::string, which it needs to be for binary_string += to work, then
std::string return_val = binary_string.substr(0, strlen(a));
If you are limited to char * then
int l = strlen(a);
char* return_val = new char[l + 1];
strncpy(return_val, binary_string, l);
return_val[l] = 0;
specify variable name in only first call to strtok(). for operations on same string again use strtok() as,
strtok(NULL,".");
to know about using strtok() read this link.
To get the binary string you want, you can follow this procedure,
for(i = 4; i > 0; i--){
dot = strtok(s, ".");
if (dot != NULL){
j = atoi(dot);
sum=sum+j;
s = strok(NULL, ".");
}
else{
k = atoi(s);
sum=sum+j;
}
//printf("%s\n", dot);
}
binarystring=dec2bin(sum);
you can reduce this loop and use,
dot = strtok(s, ".");
while (dot != NULL)
{
j = atoi(dot);
sum=sum+j;
s = strok(NULL, ".");
}
binarystring=dec2bin(sum);
here instead of adding binary number, you can add integers and then convert the sum to binary. the result will be same number right.dec2bin() should convert decimal to binary and return binary number as string. then you add code similar to this to make binary_string length same as length of a,
strcpy(tempstring,"0");
for(i=strlen(a)-strlen(binary_string);i>0;i--)
{
strcat(tempstring,binary_string);
strcpy(binary_string,tempstring);
strcpy(tempstring,"0");
}

Splitting strings and unscrambling them

I have an assignment that requires us to split a string and unscramble it. For example:
"rsedreve*_emth_*kema*_ot_*si*_skta_*uryo"
becomes:
"Your task is to make them reversed."
So far for code, I have just splitting the string:
char secondString[50];
char *secondString_ptr;
strcpy(secondString, "rsedreve*_*emth*_*kema*_*ot*_*si*_*skta*_*uryo");
secondString_ptr = strtok(secondString, "*_*");
while(secondString_ptr != NULL){
printf("%s ", secondString_ptr);
secondString_ptr = strtok(NULL, "*_*");
}
Output:
rsedreve emth kema ot si skta uryo
Obviously, the pattern here is to start at half the length of these tokens, add these characters to a char[] and then add the characters at the beginning of each tokens to the end. Can someone help me out and show me how to do this?
As you have split the string, you need to unscramble them. I think the easiest way to unscramble this is to swap the appropriate letters.
So you find the middle, then swap with the beginning and so on. For example, if you have "123456", you swap 1 and 4, then 2 and 5, then 3 and 6.
Here is a basic function that could do this:
char* unscramble(char *input)
{
int len = strlen(input);
int half = len >> 1;
int i;
for (i=0 ;i<half; i++)
{
int temp = input[i];
input[i] = input[half+i];
input[half+i] = temp;
}
return input;
}
Rather than simply printing each token, find the length of the token, do the unscrambling, shove it onto a stack, and print it out in reverse.
Edit: edited to be less of a complete solution but rather helpful snippets.
You can use an array, for example, as a simple 'stack'
char *pseudoStack[MAX_WORDS];
int stackPos = 0;
Add to the stack like this
pseudoStack[stackPos] = unscrambled;
stackPos++;
And print like this
for (i = stackPos - 1; i >= 0; i--) {
printf("%s ", pseudoStack[i]);
free(pseudoStack[i]);
}
Unscrambling can be done in precisely the manner you described. Don't forget to malloc so that you don't change the original string and so that you can keep the string after the loop ends.
char *unscrambled = malloc(MAX_WORD_LENGTH * sizeof(char));
int unscrambledPos = 0;
for (i = middle; i < wordLength; i++) {
unscrambled[unscrambledPos] = secondString_ptr[i];
unscrambledPos++;
}
for (i = 0; i < middle; i++) {
unscrambled[unscrambledPos] = secondString_ptr[i];
unscrambledPos++;
}
unscrambled[wordLength] = '\0';
Also don't forget the null character at the end!
While it's rather verbose, at least this way you can see the reasoning in each step.
Is there a policy on stackoverflow about homework questions though...?
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
main()
{
char secondString[50];
char *secondString_ptr;
int i,j,n,stack_pointer=0;
char *Word;
char *stack[50];
strcpy(secondString, "rsedreve*_*emth*_*kema*_*ot*_*si*_*skta*_*uryo");
secondString_ptr = strtok(secondString, "*_*");
while(secondString_ptr != NULL){
n=strlen(secondString_ptr);
Word=(char *)malloc(n);
/*the second half and the first half form the meaningful word*/
/*so split the word into two part and assign to the variable. Like this*/
for(i=n/2,j=0;i<n;i++)
Word[j++]=secondString_ptr[i];
for(i=0;i<n/2;i++)
Word[j++]=secondString_ptr[i];
Word[j]='\0';
/*put all this word in the stack and increment the pointer*/
secondString_ptr = strtok(NULL, "*_*");
}
stack[stack_pointer]=NULL;
for(i=stack_pointer-1;i>=0;i--)
printf("%s ",stack[i]);
printf("\n");
}
This is the algorithm for your requirement.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int unscrambling(char *str){
char *p = strtok(str, "*_");
if(p){
char temp[50];
int len = strlen(p);
int len1 = len >> 1;
int len2 = len - len1;
//char temp[len2];
/*
memcpy(temp, p, len2);
memcpy(p, p+len2, len1);
memcpy(p+len1, temp, len2);
*/
memcpy(temp, p, len1);
memcpy(p, p+len1, len2);
memcpy(p+len2, temp, len1);
if(unscrambling(NULL))
*p = toupper(*p);
if(str)
printf("%s.\n", p);
else
printf("%s ", p);
return 0;
}
return 1;
}
int main(){
char string[50];
strcpy(string, "rsedreve*_*emth*_*kema*_*ot*_*si*_*skta*_*uryo");
unscrambling(string);
strcpy(string, "rsedreve*_emth_*kema*_ot_*si*_skta_*uryo");
unscrambling(string);
return 0;
}

Resources