Assuming there is a function like this
int foo (char** str, int x)
{
char* p = *str + x;
foo2(&p); // declared as int foo2 (char** );
}
(oversimplified of course, the real function is recursive and much more complicated)
I've tried to do this:
int foo (char** str, int x)
{
foo2(&(*str + x));
}
But the compiler failed with error:
error: lvalue required as unary '&' operand
Why did the compiler shoot out with this error and how do I pass the pointer to a pointer to string x-byte(s) forwards, without declaring a variable and use its own address?
EDIT
Seems like there is some misunderstanding so I will post a complete simulation of what I want to achieve.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* string = "This is a sample string.";
char* ptr;
int randomizer;
int receive_string (char* buffer, int size) // recv
{
int i = 0;
if(ptr == NULL)
ptr = string;
for(i = 0; *ptr != '\0' && i < size; ptr++)
{
if(randomizer == 2)
{
randomizer++;
break;
}
buffer[i] = *ptr;
i++;
randomizer++;
}
if(*ptr == '\0')
{
buffer[i] = *ptr;
i++;
}
return i;
}
int read_string (char* *buffer, int size, int alloc)
{
int bytes = 0;
printf("Reading string..\n");
if(*buffer == NULL && alloc == 1)
{
printf("Allocating buffer..\n");
*buffer = calloc(size, sizeof(char));
}
bytes = receive_string(*buffer, size);
if(bytes == (-1))
{
return(-1);
}
if(bytes == 0)
{
return 0;
}
if(bytes < size)
{
char* p = *buffer + bytes;
//int temp = read_string(&p, size - bytes, 0); // works
//int temp = read_string(&(char *){&(*buffer)[bytes]}, size - bytes, 0); // works
int temp = read_string(buffer + bytes, size - bytes, 0); // doesn't work
if(temp > 0)
bytes += temp;
else return bytes;
}
return bytes;
}
int main()
{
char* buffer = NULL;
int bytes = read_string(&buffer, strlen(string) + 1, 1);
printf("[%u][%s]\n", bytes, buffer);
if(buffer)
free(buffer);
return 0;
}
The randomizer is the dumbest quickie to "simulate" a recv() that can not receive all bytes. This implementation simulates recv() but instead of reading from a socket queue it reads from a global string.
(*str + x) is not an lvalue as it is a temporay value that does not have an address so you cannot take its address with &. Even if the compiler stored the value in a temporary variable in RAM so its address could be taken how would you reference its value afterwards if foo2() modified the contents of the temporay variable.
Therefore you need to store the value in a temporary variable yourself.
if you want to pass the pointer to pointer to the particular char
foo2(&(char *){&(*str)[x]});
or
I think the following code is what you are trying to do. For kicks, I made it recursive and tested it with the alphabet for a string. Variables cnt and lmt need to be global. It will show a shrinking string if you run it. Just be sure to keep p and lmt small enough to not overflow the string.
void foo(char *s, int p) {
cnt++;
printf("%s\n", s);
if(cnt != lmt) foo(&s[p], p);
}
Related
I am writing a program to print out any line input that is longer than 3.
It works for some fairly long input lines, but for the string that is too long, I got a error message of memory corruption
*** Error in `./print-80': malloc(): memory corruption (fast): 0x00000000022ff030 ***
I don't know where the error is from. Can anyone explain me why there is the error and how to fix it?
Below is the program
#include <stdio.h>
#include <stdlib.h>
#define LIMIT 3
#define LEAST_LENGTH 3
//function prototype
void copy(char* from, char* to);
int getline(char* s, int capacity);
int increase_capacity(char* s, int capacity);
int main(void)
{
int length, i;
char* line = calloc(LIMIT, sizeof(char));
while ((length = getline(line, LIMIT)) > 0)
{
if (length > LEAST_LENGTH)
printf("Output: %s\n", line);
//reset the line
for (i = 0; i < length; i++)
*(line + i) = 0;
}
free(line);
return 0;
}
int getline(char* line, int capacity)
{
int c, length;
length = 0;
while ((c = getchar()) != EOF && c != '\n')
{
if (length > (capacity - 1))
{
capacity = increase_capacity(line, capacity);
printf("Address of line after increasing cap: %p\n", line);
}
line[length++] = c;
}
if (c == '\n')
line[length++] = '\0';
return length;
}
int increase_capacity(char* s, int capacity)
{
int i;
capacity *= 2;
char *new_s = calloc(capacity, sizeof(char));
copy(s, new_s);
s = new_s;
free(new_s);
return capacity;
}
void copy(char* from, char* to)
{
int i = 0;
while ((to[i] = from[i]) != '\0')
++i;
}
Your increase_capacity function can change the address at which the data is stored. But it doesn't return this information to its caller. So getline will write to the old buffer address. Similarly, main has no way to get the new address, so it will access the old address and free a block that may already be freed.
Also, your increase_capacity function allocates memory to hold the data and then frees that memory. That leaves no place to hold the data!
int increase_capacity(char* s, int capacity)
{
int i;
capacity *= 2;
char *new_s = calloc(capacity, sizeof(char)); // allocate a larger block
copy(s, new_s); // copy the data into the larger block
s = new_s; // stash a pointer to the larger block in a local
free(new_s); // free the block?!
return capacity;
}
So we allocate a new block, copy the data into it, and then free it. That makes no sense, we need to keep the larger block since that's the whole point of a function to increase capacity. We also don't return the address of the new block, so even if we didn't free it, no other code could access it and we'd just wind up leaking it. Double oops.
I suggest you create a struct that holds both the pointer to the block and its size. Pass a pointer to that struct to functions like increase_capacity so it can modify the pointer and the size in the structure and callers can see the changes.
I need to dynamically append a char to a string, so I'm using realloc() to add more memory as I need it.
I'm new to C (coming from Python) so I've been reading a lot and this was the best I could do:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void append_to(char *array, char value) {
size_t buffer = (strlen(array) * sizeof(char)) + sizeof(char);
char *new_array = realloc(array, buffer);
if (new_array == NULL) {
printf("CRITICAL ERROR\n");
exit(-1);
}
array = new_array;
int position = strlen(array);
array[position] = value;
}
int main() {
char *list = malloc(sizeof(char));
for (int i = 1; i < 26; i++){
append_to(list, 'a');
printf("%d -> %s\n", i, list);
}
}
This is just an example to showcase the issue. The code runs flawlessly until iteration 24, see below:
1 -> a
2 -> aa
[...] //omitted
23 -> aaaaaaaaaaaaaaaaaaaaaaa
24 -> aaaaaaaaaaaaaaaaaaaaaaaa
25 ->
What am I missing?
First you forget to add another NUL char at the end of your c-string.
Second, realloc may change the memory location of the data, but you passed the list as value, so the relocation is not visible in the case of data relocation.
That should lokks like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void append_to(char **array, char value) { // pass pointer's address
size_t buffer = (strlen(*array) * sizeof(char)) + sizeof(char) + sizeof(char); // one more to tackle the end of the string
char *new_array = realloc(*array, buffer);
if (new_array == NULL) {
printf("CRITICAL ERROR\n");
exit(-1);
}
*array = new_array;
int position = strlen(*array);
(*array)[position] = value;
(*array)[position+1] = 0; // end of string
}
int main() {
char *list = malloc(sizeof(char));
list[0] = 0; // end of string
for (int i = 1; i < 26; i++){
append_to(&list, 'a'); // pass address of array so that it can be changed by the call
printf("%d -> %s\n", i, list);
}
free(list); // always explicitly free unused resources
}
You didn't receive array as a double pointer, so you can't reassign the caller's pointer when realloc has to move the allocation.
To fix,
// Receive double pointer
void append_to(char **array, char value) {
// Add dereferencing as needed
size_t buffer = (strlen(*array) + 2) * sizeof(char);
char *new_array = realloc(*array, buffer);
if (new_array == NULL) {
printf("CRITICAL ERROR\n");
exit(-1);
}
*array = new_array;
int position = strlen(*array);
array[0][position] = value;
array[0][position+1] = '\0'; // Explicitly NUL terminate, don't assume new memory is zeroed
}
int main() {
char *list = malloc(sizeof(char));
for (int i = 1; i < 26; i++){
append_to(&list, 'a'); // Pass address of list
printf("%d -> %s\n", i, list);
}
}
I am using the below function to replace a sub-string in a given string
void ReplaceSubStr(char **inputString, const char *from, const char *to)
{
char *result = NULL;
int i, cnt = 0;
int tolen = strlen(to);
int fromlen = strlen(from);
if (*inputString == NULL)
return;
// Counting the number of times old word
// occur in the string
for (i = 0; (*inputString)[i] != '\0'; i++)
{
if (strstr((&(*inputString)[i]), from) == &(*inputString)[i])
{
cnt++;
// Jumping to index after the old word.
i += fromlen - 1;
}
}
// Making new string of enough length
result = (char *)malloc(i + cnt * (tolen - fromlen) + 1);
if (result == NULL)
return;
memset(result, 0, i + cnt * (tolen - fromlen) + 1);
i = 0;
while (&(*inputString))
{
// compare the substring with the result
if (strstr(*inputString, from) == *inputString)
{
strncpy(&result[i], to, strlen(to));
i += tolen;
*inputString += fromlen;
}
else
{
result[i++] = (*inputString)[0];
if ((*inputString)[1] == '\0')
break;
*inputString += 1;
}
}
result[i] = '\0';
*inputString = result;
return;
}
The problem with the above function is memory leak. Whatever memory is allocated for inputString will be lost after this line.
*inputString = result;
since I am using strstr and moving pointer of inputString *inputString += fromlen; inputString is pointing to NULL before the above line. So how to handle memory leak here.
Note: I dont want to return the new memory allocated inside the function. I need to alter the inputString memory based on new length.
You should use a local variable to iterate over the input string and avoid modifying *inputString before the final step where you free the previous string and replace it with the newly allocated pointer.
With the current API, ReplaceSubStr must be called with the address of a pointer to a block allocated with malloc() or similar. Passing a pointer to local storage or a string literal will have undefined behavior.
Here are a few ideas for improvement:
you could return the new string and leave it to the caller to free the previous one. In this case, you would take the input string by value instead of by address:
char *ReplaceSubStr(const char *inputString, const char *from, const char *to);
If the from string is empty, you should either insert the to string between each character of the input string or do nothing. As posted, your code has undefined behavior for this border case.
To check if the from string is present at offset i, use memcmp instead of strstr.
If cnt is 0, there is nothing to do.
You should return an error status for the caller to determine if memory could be allocated or not.
There is no need to initialize the result array.
avoid using strncpy(). This function has counter-intuitive semantics and is very often misused. Read this: https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/
Here is an improved version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int ReplaceSubStr(char **inputString, const char *from, const char *to) {
char *input = *inputString;
char *p, *q, *result;
size_t cnt;
size_t tolen = strlen(to);
size_t fromlen = strlen(from);
if (input == NULL || fromlen == 0)
return 0;
// Counting the number of times old word occurs in the string
for (cnt = 0, p = input; (p = strstr(p, from)) != NULL; cnt++) {
p += fromlen;
}
if (cnt == 0) // no occurrence, nothing to do.
return 0;
// Making new string of enough length
result = (char *)malloc(strlen(input) + cnt * (tolen - fromlen) + 1);
if (result == NULL)
return -1;
for (p = input, q = result;;) {
char *p0 = p;
p = strstr(p, from);
if (p == NULL) {
strcpy(q, p0);
break;
}
memcpy(q, p0, p - p0);
q += p - p0;
memcpy(q, to, tolen);
q += tolen;
p += fromlen;
}
free(*inputString);
*inputString = result;
return 0;
}
int main() {
char *p = strdup("Hello world!");
ReplaceSubStr(&p, "l", "");
printf("%s\n", p); // prints Heo word!
free(p);
return 0;
}
You cannot obviously free the input as it can be a literal, some memory you don't control. That would cripple your function even more than now.
You could return the old value of inputString so you'd be able to free it if needed.
char *ReplaceSubStr(char **inputString, const char *from, const char *to)
{
char *old_string = *inputString;
...
return old_string;
}
The caller is responsible to free the contents of old_string if needed.
If not needed (we have to workaround the char ** input by assigning a valid writable array to a pointer to be able to pass this pointer:
char input[]="hello world";
char *ptr = input;
ReplaceSubStr(&ptr, "hello", "hi");
// input is now "hi world" in a different location
free(ptr); // when replaced string isn't needed
if needed:
char *input = strdup("hello world");
char *old_input = ReplaceSubStr(&input, "hello", "hi");
free(old_input);
or just
free(ReplaceSubStr(&input, "hello", "hi"));
then always (when replaced string isn't needed):
free(input);
The only constraint is that you cannot use a constant string literal as input (const char *input = "hello world") because of the prototype & the possible return of a char * to pass to free.
I use this code, with this structure, im trying to make function to add item into array of this structure
typedef struct goods{
char *name;
int num;
} goods;
void addWord(char *what, goods *where, int pnr, int *arrsize, int n){
if (pnr >= *arrsize){
where = (goods*)realloc(where,*arrsize*2*sizeof(goods*));
*arrsize*=2;
}
where[pnr].name = (char*)malloc(strlen(what)*sizeof(char));
strcpy(where[pnr].name,what);
where[pnr].num = n;
}
in main function i have this:
int extstore = 1;
goods *store = (goods*)malloc(1*sizeof(goods*));
addWord(line, store, nr, &extstore, n);
Why am I getting an "invalid next size" runtime-error on the line where = (goods*)realloc(where,*arrsize*2*sizeof(goods*)); in addWord()?
EDIT:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct goods{
char *name;
int r;
} goods;
int main()
{
int linelen, i, nr = 0, current_r;
char *line = NULL;
size_t len = 0;
int extstore = 1;
goods *store;
store = malloc(extstore*sizeof(goods*));
while (1){
while ((linelen = getline(&line, &len, stdin)) != -1){
if (line[linelen - 1] == '\n'){
line[linelen - 1] = '\0';
}
linelen = strlen(line);
if (line[0] == '#'){
if (sscanf(line,"#%d",¤t_r) != 1){
printf("bad input.");
return 0;
} else continue;
}
if (nr >= extstore){
store = realloc(store,extstore * sizeof(goods*) * 2);
extstore*=2;
}
store[nr].name = malloc(strlen(line)*sizeof(char));
strcpy(store[nr].name,line);
store[nr].r = current_r;
nr++;
}
if (linelen == -1) break;
}
printf("\n");
for (i = 0;i < nr;i++){
printf("%s, [id:%d]\n", store[i].name, store[i].r);
}
return 0;
}
extstore * sizeof(goods*) * 2
should be extstore * sizeof(goods) * 2 because the space for structures should be allocated - not just for pointers.
There is a fundamental problem in your code. You are passing pointer by value, which means that any change made to a pointer (not the variable pointed to, but the pointer itself) will not be visible from outside the function. You should pass a pointer by pointer instead, and you should check the result returned from realloc. Secondly, don't assign result of realloc back to same pointer - in case of failure you will lost pointer to memory -> thus, memory leak will occur.
To pass pointer by pointer:
void addWord( char *what, goods **where, size, ...) {
if ( *where == NULL) return; // nothing to do
if ( size < 1) return; // it would result in realloc=free call
goods *res = NULL;
res = realloc( *where, size * sizeof( goods));
if ( res != NULL) {
*where = res;
}
else {
// Error (re)allocating memory
// If realloc() fails the original block is left untouched,
// it is not freed or moved, so here *where is unchanged
}
And there is no need in C to cast a result from malloc.
* Error in `path': realloc(): invalid next size: 0x0000000000ec8010 *
This failure must be because "where" is invalid due to a heap corruption earlier in the execution.
C is pass-by-value.
Which means changing an argument in the function does not change the expression it was initialized from.
Thus, the first time realloc moves the memory, the pointer in main will be bad.
To correct that, either use an extra level of indirection, or preferably return the new value as the result.
(Anyway, you should check for allocation failure (malloc and realloc),
and you should not cast from void* to any pointer-type in C.)
EDIT: I should add how I have this all set up. The struct definition and prototypes are in mystring.h. The function definitions are in mystring.c. The main is in mystringtest.c. For mystring.c and mystringtest.c, I have #include "mystring.h" at the top. I'm compiling like gcc -o test.exe mystring.c mystringtest.c. Not sure if any of that matters, but I'm new with C so I'm just trying to include everything.
I have a good deal of experience with Java but am pretty new to C. I imagine this is related to pointers and memory but I'm totally at a loss here for what's going on. Here's my code:
typedef struct {
char *chars;
int length;
int maxSize;
} String;
int main() {
char *a;
a = readline();
String *s = newString(a);
int b = length(s);
printf("length is %d \n", b);
}
I run the program and enter "hello" (as prompted by readline()). I've stepped through the program and after length(s), s->chars is still a pointer to the array of chars 'hello'. After the print statement, s->chars becomes a pointer to the array of chars 'Length is %d \n'. I'm totally at a loss for what I'm doing wrong. I'm working on a virtual machine if that matters at all. Any help is greatly appreciated. I'll give the code for newString and length too.
int length(String *s) {
char *temp = s->chars;
char b = *temp;
int count;
if (b == '\0') { count = 0; }
else { count = 1; }
while (b != '\0') {
b = *(temp+count);
count++;
}
return count;
}
String *newString(char *s) {
String st;
st.length = 20;
st.maxSize = MAXCHAR;
char *temp = malloc(20 * sizeof(char));
char b = *s;
int count = 0;
while (b != '\0') {
*(temp + count) = b;
count++;
b = *(s+count);
if (count == st.maxSize) { break; }
if (count == st.length) {
st.length = st.length + 20;
temp = realloc(temp, st.length * sizeof(char));
}
}
st.chars = temp;
return &st;
}
String *newString(char *s) {
String st;
...
return &st;
}
You are returning a pointer to a local variable. After newString returns, the local variable no longer exists, so you have a dangling pointer.
Either allocate st with malloc, or return it by value.
you must null terminate the string after the while loop, you have not left space for the null terminator. Also I don't see why you need to realloc
//using strlen will eliminate the need for realloc, +1 is for the null terminator
int len = strlen(s)
char *temp = malloc((len * sizeof(char)) +1);
//null terminate
*(temp+count) = '\0';
st.chars = temp;