tearing my hair out over C strings over here. I have a function in a project which returns a char * pointer.
I need to change an element of that string before using it. Everything I read says just use a char array with the char[] format, but this is not compatible with my project in its current state, if at all.
I have desperately been looking for someway to copy the first n characters to a second char pointer, add the updated value and then concat the remainder of the initial pointer (minus the original value that was updated) that doesnt take 40 lines of code.
Every attempt to use fgetc for this has failed to write the unsigned int to the 'updated pointer'. Do I need to sprintf the unsigned int into a char buffer or something? why does this feel so ridiculously complicated?
An example of a failed attempt at the first steps of the desired behavior:
int main() {
char *s;
s = "babado = lubidee = popop =pew";
char * s1;
s1 = malloc(10);
memset(s1,'0',9);
strcpy(s1,fgetc(s));
for (int i = 0; i<4; i++){
strcat(s1,fgetc(s));
}
printf("%s",s1);
return 0;
}
If you need to just copy a string to another pointer,
.
.
char *newptr;
//Allocate memory for new pointer
int i=0;
while(i<n) //first n characters
*(newptr+i)=*(returnedptr+i);. //returnedptr is your initial ptr
//Add new value
i++;
while( *(returnedptr+i)!='\0')
*(newptr+i)=*(returnedptr+i);
.
.
Related
I'm working in a little project, i have some names stored in a struct (example: Name1, Name2) and I need to split each one and store it in a array so I can call then each name separately (printf("%s", vet[1]) should print only "Name2").
This is my code:
int main(){
char temp[100];
LIGA *vetLiga;
int reference;
int quantiy;
separarEquipas(vetLiga, temp, reference, quantity);
}
int separarEquipas(LIGA *p, char vet[100], int vPesquisa, int n){
int i, nr, a;
char *ptr;
char *str;
for(i=0;i<n;i++){
if (p->id == vPesquisa){
nr = p->nrEquipas;
strcpy(str, p[i].eqLiga);
ptr = strtok(str, " ,");
while(ptr != NULL)
{
vet[a++] = ptr; //here I'm trying to store each word in a position of the array
ptr = strtok(NULL, " ,");
}
}
p++;
}
return nr;
}
The issue is inside the while where I try to store each token in the array but it keeps crashing the terminal. I tried in different ways like using strcpy and memcpy as other posts suggest but nothing :(.
Some errors that i got while trying to find a solution:
[Warning] assignment makes integer from pointer without a cast;
[Warning] passing argument 1 of 'strcpy' makes pointer from integer without a cast.
Hope you can help me,
Thank you!
You didn't post the full code, so from what I can see vetLiga that in separarEquipas becomes p is uninitialised.
Another issue is that you try to use str in strcpy without allocating memory for it. You need to do that
char *str = malloc( max_number_of_characters_in_str );
Then here:
vet[a++] = ptr; //here I'm trying to store each word in a position of the array
You are doing exactly what you said in the comment. However you can't store a word into the space for a single character. vet needs to be a 2D array or if you want even an array of pointers to char.
If you want further help include the whole program.
In main, vetLiga is never assigned a value, but maybe you abbreviated the code.
In separarEquipas you have the following:
char *str;
strcpy(str, p[i].eqLiga)
So you are copying a string to a random location in memory.
I want to implement a queue which holds 10 elements of char * array. I searched on the internet but couldn't find enough solutions.
I have a char array:
char str[50]:
char *arr[5];
And the user enters some string with backspace character e.g "Hello I am computer". The string is in str[] array. I token them with strtok() function and assign it to the arr[].Then it becomes:
//arr[0] = "Hello"
//arr[1] = "I"
//arr[2] = "am"
//arr[3] = "computer"
It is ok until now, I am doing it correctly.
Now my question is how to hold this whole arr array in queue's first node or element. There are lots of examples about queue that holding int values and they are easy to understand, but I couldn't do the char * version.
As far as I understood your question you need to implement a queue of type string.
You can do it as you do with any other queue.But instead of int it would of type char* you would also need to pass length of the word so you could dereference that many number of char starting from the char pointer till length of the word.
void Enqueue(char* x, int len)
{
// if empty
front = rear = 0;
// else
rear = (rear+1);
char ch[100];
for(int i=0;i<len;i++) {
ch[i] = *(x+i);
}
Arr[rear] = ch;
}
First of all you have to be careful when saving an address to a variable that you want to use later. You have to ensure that the address hold by the pointer is still valid when you read from it:
int main()
{
char str[] = "Hello I am computer"; // "Hello I am computer" is stored on the stack
AddStringToQueue(str[0]);
}
// str could be overwritten by another function who allocates local variables
As you said in the comment you should use void* malloc(sizeof("Hello I am computer")) which return the start pointer of your allocated memory.
The other thing is why you want to store the string as tokens? Wouldn't it be easier to store the whole string ("Hello I am computer") and use the first character as your start address for the string? If you need it as tokens you maybe can call strtok() after you read out the queue.
Let me make an example:
#define QUEUE_MAX 10
int QueuePos = 0;
char* Queue[QUEUE_MAX];
memset(Queue, NULL, sizeof(Queue));
// call AddStringToQueue("Hello I am computer"); anywhere
void AddStringToQueue(char* string)
{
char* ptr = (char*)malloc(sizeof(string));
memcpy(ptr, string, sizeof(string));
Queue[QueuePos++] = ptr;
if (QueuePos == QUEUE_MAX) QueuePos = 0; // overwrites Queue if max. is reached
}
I am not sure if you mean this.
Hope it helps.
PS: I didn't compiled this so i am not sure if it works, it should just be an example.
I am doing a bit of studying about C pointers and how to transfer them to functions, so I made this program
#include <stdio.h>
char* my_copy(pnt);
void main()
{
int i;
char a[30];
char* p,*pnt;
printf("Please enter a string\n");
gets(a);
pnt = a;
p = my_copy(pnt);
for (i = 0; i < 2; i++)
printf("%c", p[i]);
}
char* my_copy(char* pnt)
{
char b[3];
char* g;
g = pnt;
b[0] = *pnt;
for (; *pnt != 0; pnt++);
pnt--;
b[1] = *pnt;
b[2] = NULL;
return b;
}
It's supposed to take a string using only pointers and send a pointer of the string to the function my_copy and return a pointer to a new string which contains the first and the last letter of the new string. Now the problem is that the p value does receive the 2 letters but I can't seem to print them. Does anyone have an idea why?
I see five issues with your code:
char* my_copy(pnt); is wrong. A function prototype specifies the types of the parameters, not their names. It should be char *my_copy(char *).
void main() is wrong. main should return int (and a parameterless function is specified as (void) in C): int main(void).
gets(a); is wrong. Any use of gets is a bug (buffer overflow) and gets itself has been removed from the standard library. Use fgets instead.
b[2] = NULL; is a type error. NULL is a pointer, but b[2] is a char. You want b[2] = '\0'; instead.
my_copy returns the address of a local variable (b). By the time the function returns, the variable is gone and the pointer is invalid. To fix this, you can have the caller specify another pointer (which tells my_copy where to store the result, like strcpy or fgets). You can also make the function return dynamically allocated memory, which the caller then has to free after it is done using it (like fopen / fclose).
You're returning an array from my_copy that you declared within the function. This was allocated on the stack and so is invalid when the function returns.
You need to allocate the new string on the heap:
#include <stdlib.h>
b = malloc(3);
if (b) {
/* Do your funny copy here */
}
Don't forget to free() the returned string when you've finished with it.
I have a pointer:
char * name;
it contains the string "test:case"
And I'm calling another function with it, and trying to store it in a structure. However, I want to capitalize the entire string first, but It doesn't seem to work.
void func(char * name) {
int i;
List * l;
l = malloc(sizeof(List));
for(i=0; i< strlen(name); i++) {
name[i] = toupper(name[i]);
}
l->name = name;
//CALL A FUNCTION TO LATER FREE ALLOCATED MEMORY
}
Where List is a struct that has a member (char *) named name.
This however, seg faults. I can't go about using non pointers in my case. As I have to use pointers and not character arrays, I'm trying to use toupper in every value of the char pointer, however this doesn't seem to work.
You're getting a segfault because the original string is presumably a literal, and it's not modifiable. You need to make a copy of it first.
void func(char * name) {
List * l;
l = malloc(sizeof(List));
name = strdup(name); // make a copy of name
for (char *p = name; *p; p++) {
*p = toupper(*p);
}
l->name = name;
}
Note that when you later free l, you'll first need to free l->name.
Since you only set the pointer l->name to name, this will crash the moment the original name is no longer there (maybe it was only on the stack?) and l->name is accessed. You need to malloc() space the size of strlen(name)+1, copy name there and set l->name to that address.
You have allocated the List, but not the name string itself.
You need to do:
l=malloc(sizeof(List));
l->name=(char*)malloc(strlen(name)+1); // You need to cater for the the final null char.
There are a few additional issues with your code, here is the correct one (didn't compile it, probably close to okay):
void func(char *name) {
List * l;
l = (List*)malloc(sizeof(List));
l->name = (char*)malloc(strlen(name)+1);
for(char *r=name, char *w=l->name; *r; ++r,++w) {
*w = toupper(*r);
}
*++w='\0';
}
And at every iteration, this code does not evaluate again and again strlen, which would be very bad.
There are two mistakes in the code.
char * name
The variable name contains a pointer to a string (i.e., an array of char).
When you write this:
name[i] = toupper(name[i]);
you are changing the original char itens of the string, if it is not a pointer to a constant string. If that is the case, it is a segmentation fault.
The other mistake is here:
l->name = name;
You are just assigning to the variable within the structure the pointer which was passed on through the variable name to the function. You should make a copy, like this:
strcpy(l->name, name);
This functions copies all the contents from the second argument to the first.
But that's not a good solution. If name contains a pointer to a constant string, it's still segmentation fault.
I'll rewrite your code:
void func(char * name) {
int i;
List * l;
l = malloc(sizeof(List));
char *buffer[strlen(name)]; //buffer of the contents pointed by *name* to upper case, initialized as empty string
for(i=0; i< strlen(name); i++) {
buffer[i] = toupper(name[i]);
}
buffer[i] = '\0'; //closing the string in i = strlen(name)
strcpy(l->name, buffer);
//CALL A FUNCTION TO LATER FREE ALLOCATED MEMORY
}
That way, you manipulate a copy of the original string, and than you make a copy of the buffer to the variable in the structure.
If you do this:
l->name = buffer;
you're only copying a local pointer, which will be gone with the end of the function.
I suggest you learn more about pointers, arrays and strings in C. In essence, a string is a array of char, with a '\0' in the final position. An empty string s has '\0' in s[0].
Edit: if you're used to languages which makes a copy of the string like this:
string1 = string2
you should always have in mind that, in C, that's pointer assignment. So, in C, that code would have to be written like this:
strcpy(string1, string2);
Hope that helps.
I have a program that accepts a char input using argv from the command line. I copy the input argv[1] using strcpy to a pointer called structptr(it goes to structptr->words from struct) where memory has been allocated. I then copy character by character from the memory that the pointer structptr points to another pointer called words that points to memory that has been allocated. After i've copied one character i print that element [c] to make sure that it has been copied correctly(which it has). I then finish copying all of the characters and return the result to a char pointer but for some reason it is blank/null. After each copying of the characters i checked if the previous elements were correct but they don't show up anymore([c-2], [c-1], [c]). Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct StructHolder {
char *words;
};
typedef struct StructHolder Holder;
char *GetCharacters(Holder *ptr){
int i=0;
char *words=malloc(sizeof(char));
for(i;i<strlen(ptr->words);i++){
words[i]=ptr->words[i];
words=realloc(words,sizeof(char)+i);
}
words[strlen(ptr->words)]='\0';
return words;
}
int main(int argc, char **argv){
Holder *structptr=malloc(sizeof(Holder));
structptr->words=malloc(strlen(argv[1]));
strcpy(structptr->words, argv[1]);
char *charptr;
charptr=(GetCharacters(structptr));
printf("%s\n", charptr);
return 0;
At first I thought this was the problem:
char *words=malloc(sizeof(char)) is allocating 1 byte (sizeof 1 char). You probably meant char *words = malloc(strlen(ptr->words)+1); - You probably want to null check the ptr and it's member just to be safe.
Then I saw the realloc. Your realloc is always 1 char short. When i = 0 you allocate 1 byte then hit the loop, increment i and put a char 1 past the end of the realloced array (at index 1)
Also your strcpy in main is has not allocated any memory in the holder.
In these two lines,
structptr->words=malloc(strlen(argv[1]));
strcpy(structptr->words, argv[1]);
need to add one to the size to hold the nul-terminator. strlen(argv[1]) should be strlen(argv[1])+1.
I think the same thing is happening in the loop, and it should be larger by 1. And sizeof(char) is always 1 by definition, so:
...
words=realloc(words,i+2);
}
words=realloc(words,i+2); // one more time to make room for the '\0'
words[strlen(ptr->words)]='\0';
FYI: Your description talks about structptr but your code uses struct StructHolder and Holder.
This code is a disaster:
char *GetCharacters(Holder *ptr){
int i=0;
char *words=malloc(sizeof(char));
for(i;i<strlen(ptr->words);i++){
words[i]=ptr->words[i];
words=realloc(words,sizeof(char)+i);
}
words[strlen(ptr->words)]='\0';
return words;
}
It should be:
char *GetCharacters(const Holder *ptr)
{
char *words = malloc(strlen(ptr->words) + 1);
if (words != 0)
strcpy(words, ptr->words);
return words;
}
Or even:
char *GetCharacters(const Holder *ptr)
{
return strdup(ptr->words);
}
And all of those accept that passing the structure type makes sense; there's no obvious reason why you don't just pass the const char *words instead.
Dissecting the 'disaster' (and ignoring the argument type):
char *GetCharacters(Holder *ptr){
int i=0;
OK so far, though you're not going to change the structure so it could be a const Holder *ptr argument.
char *words=malloc(sizeof(char));
Allocating one byte is expensive — more costly than calling strlen(). This is not a good start, though of itself, it is not wrong. You do not, however, check that the memory allocation succeeded. That is a mistake.
for(i;i<strlen(ptr->words);i++){
The i; first term is plain weird. You could write for (i = 0; ... (and possibly omit the initializer in the definition of i, or you could write for (int i = 0; ....
Using strlen() repeatedly in a loop like that is bad news too. You should be using:
int len = strlen(ptr->words);
for (i = 0; i < len; i++)
Next:
words[i]=ptr->words[i];
This assignment is not a problem.
words=realloc(words,sizeof(char)+i);
This realloc() assignment is a problem. If you get back a null pointer, you've lost the only reference to the previously allocated memory. You need, therefore, to save the return value separately, test it, and only assign if successful:
void *space = realloc(words, i + 2); // When i = 0, allocate 2 bytes.
if (space == 0)
break;
words = space;
This would be better/safer. It isn't completely clean; it might be better to replace break; with { free(words); return 0; } to do an early exit. But this whole business of allocating one byte at a time is not the right way to do it. You should work out how much space to allocate, then allocate it all at once.
}
words[strlen(ptr->words)]='\0';
You could avoid recalculating the length by using i instead of strlen(ptr->words). This would have the side benefit of being correct if the if (space == 0) break; was executed.
return words;
}
The rest of this function is OK.
I haven't spent time analyzing main(); it is not, however, problem-free.