I have a string
char *str = "hello world";
I also have a int pointer
int *ptr;
How can I use these two in a function that loops over the string and prints all the chars in it?
The header function would be something like this:
void print(const int *ptr){
while(*ptr != 0){
printf("%c", (char)*ptr);
++ptr;
}
}
Now I know that I want to use the ptr to somehow reference the char ptr. But how would I do this?
I've tried doing just
ptr = str;
And tried a whole bunch of different combinations of
ptr=*str;
ptr=&str;
And so on.
I know I can iterate over the string just doing
while(*str != 0){
printf("%c",*str)
str++;
}
And that I can also do it using index elements like str[0].
But how can I use a pointer to act as the index element for the char string?
Why do you need to use int * to access char *? It is not correct and shouldn't be done so.
The main problem with it is that each time you increase you pointer ptr by 1 it is incremented by sizeof(int) bytes (which is platform dependent and varies between 2 and 4). While each character in the string is of size 1 byte.
Also when you write *ptr you actually access sizeof(int) bytes which may result in segmentation fault if ptr points to the end part of the string.
If you have no option to change the function signature do it like this:
void print(const int *ptr){
const char* char_ptr = (const char*)ptr;
while(*char_ptr != 0){
printf("%c", *char_ptr);
++char_ptr;
}
}
If all you need is just to print the string to which (for some reason) const int* ptr is pointing then you can do something like that:
void print(const int *ptr)
{
printf("%s", ptr);
}
printf won't check the type of the pointer, it will assume that the pointer is pointing to a buffer of chars and will print the whole buffer until it reachs '\0'.
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'm trying to get the length of a string using double pointers but for some reason its not displaying correctly. Some explanation would be greatly appreciated. I feel like i'm missing something simple here.
(I am aware this can be done with a single pointer.)
#include <stdio.h>
void find_length(char**);
int main() {
char* p = "this a message";
char** k = &p;
find_length(k);
return 0;
}
void find_length(char **k) {
while (*k != '\0') {
printf("%c", *k);
k++;
}
}
Ask yourself: When you have a pointer to T and you indirect through that pointer what do you get?
You get T
Now, ask yourself: When T is char, the pointer in question is char* i.e. pointer to char; what do you get when you indirect through that?
You get char
Now, ask yourself: When T is char*, the pointer in question is char** i.e. pointer to pointer to char; what do you get when you indirect through that?
You get char*
Now, ask yourself: What is the type of '\0'
It is char.
Does it make sense to compare char* with char? No, it does not. Now, you have a char*, so how could you get a char out of it? By indirecting through it of course.
Another problem is that you are incrementing k. Incrementing a pointer is allowed when it points to element of an array. Does k point to an array of pointers? It does not. There is only one char* being pointed at. If you want to iterate through the array pointed by *k, then you need to increment *k (or a copy of it).
k is pointer to pointer to char
*k is a pointer to char
**k is a char
So when you check for *k != '\0' you check that the pointer to cahr is different from zero, not if the char is different from the null terminator in the string.
When you do the k++ you increase the pointer to pointer to point at the next pointer to char.
Try this instead.
void find_length(char **k) {
char *kk = *k; // temp.
while (*kk != '\0') {
printf("%c", *kk);
kk++;
}
}
I'm working with a method that must take a pointer to a pointer. I was wondering how I would go about getting the individual char values in this variable? For example:
void spacer(char **ptr) {
int i;
for(i = 0; **ptr[i] != ' '; i++) {
printf("Is not space");
}
}
I'm unsure how to accomplish this without getting a compilation error or segmentation fault.
Assuming ptr points valid memory and *ptr does as well then(*ptr)[i] gets you a char.
If ptr is just a double layer pointer, you can move it to make a local variable to make it simpler.
char* str = *ptr;
Then access it like a normal string later on.
str[i] == ' '
Also be careful about not leaving the allocated buffer. You need to either know the length or watch out for a null terminator.
ptr is a pointer to pointer to char,so de-referencing it once will target a pointer.de-referencing it twice will target a char.
So **ptr will get you the first character.to loop over the characters you may use the following notation:
*(*ptr + i) which is equivalent to (*ptr)[i]
you may try this:
char *temp=NULL;
int i;
temp=(char *)malloc(strlen(*ptr));
memset(temp,'\0',strlen(*ptr)+1);
for(i=0;i<strlen(*ptr)+1;i++)
{
if(temp[i] != 32)
printf("not space!\n");
}
I am a beginner in C. I wanted to make strcat function using pointers. I made it but don't know what is wrong with it. I used gcc compiler and it gave segmentation fault output.
#include<stdio.h>
#include<string.h>
char scat(char *,char *);
void main()
{
char *s="james";
char *t="bond";
char *q=scat(s,t);
while(*q!='\0') printf("the concatenated string is %c",*q);
}
char *scat(char *s,char *t)
{
char *p=s;
while(*p!='\0'){
p++;
}
while(*t!='\0'){
*p=*t;
p++;
t++;
}
return p-s-t;
}
This one works:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *scat(char *,char *); /* 1: your prototype was wrong */
void main()
{
char *s="james";
char *t="bond";
char *q=scat(s,t);
printf("cat: %s\n", q); /* 2: you can use %s to print a string */
free(q);
}
char *scat(char *s,char *t)
{
char *p=malloc(strlen(s)+strlen(t)+1); /* 3: you will have to reserve memory to hold the copy. */
int ptr =0, temp = 0; /* 4 initialise some helpers */
while(s[temp]!='\0'){ /* 5. use the temp to "walk" over string 1 */
p[ptr++] = s[temp++];
}
temp=0;
while(t[temp]!='\0'){ /* and string two */
p[ptr++]=t[temp++];
}
return p;
}
You have to allocate new space to copy at the end of s. Otherwise, your while loo[ will go in memory you don't have access to.
You shoul learn about malloc() here.
It is undefined behaviour to modify a string literal and s, and eventually p, is pointing to a string literal:
char* s = "james";
s is passed as first argument to scat() to which the local char* p is assigned and then:
*p=*t;
which on first invocation is attempting to overwite the null character an the end of the string literal "james".
A possible solution would be to use malloc() to allocate a buffer large enough to contain the concatentation of the two input strings:
char* result = malloc(strlen(s) + strlen(p) + 1); /* + 1 for null terminator. */
and copy them into it. The caller must remember to free() the returned char*.
You may find the list of frequently asked pointer questions useful.
Because p goes till the end of the string and then it starts advancing to illegal memory.
That is why you get segmentation fault.
It's because s points to "james\0", string literal & you cannot modify constant.
Change char *s="james"; to char s[50]="james";.
You need to understand the basics of pointers.
a char * is not a string or array of characters, it's the address of the beginning of the data.
you can't do a char * - char* !!
This is a good tutorial to start with
you will have to use malloc
You get a segmentation fault because you move the pointer to the end of s and then just start writing the data of p to the memory directly following s. What makes you believe there is writable memory available after s? Any attempt to write data to non-writable memory results in a segmentation fault and it looks like the memory following s is not writable (which is to expect, since "string constants" are usually stored in read-only memory).
Several things look out of order.
First keep in mind that when you want to return a pointer to something created within a function it needs to have been malloc'ed somewhere. Much easier if you pass the destination as an argument to the function. If you follow the former approach, don't forget to free() it when you're done with it.
Also, the function scat has to return a pointer in the declaration i.e. char *scat, not char scat.
Finally you don't need that loop to print the string, printf("%s", string); will take care of printing the string for you (provided it's terminated).
At first, your code will be in infinte loop because of the below line. you were supposed to use curely braces by including "p++; t++ " statements.
while(*t!='\0')
*p=*t;
though you do like this, you are trying to alter the content of the string literal. which will result in undefined behavior like segmentation fault.
A sequence of characters enclosed with in double quotes are called as string literal. it is also called as "string". String is fixed in size. once you created, you can't extend its size and alter the contents. Doing so will lead to undefined behavior.
To solve this problem , you need to allocate a new character array whose size is sum of the length of two strings passed. then append the two strings into the new array. finally return the address of the new array.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char* scat(char *,char *);
void append(char *t , char *s);
int main(void)
{
char *s="james";
char *t="bond";
char *n = scat(s,t);
printf("the concatenated string is %s",n);
return 0;
}
char* scat(char *s,char *t)
{
int len = strlen(s) + strlen(t);
char *tmp = (char *)malloc(sizeof(char)* len);
append(tmp,s);
append(tmp,t);
return tmp;
}
void append(char *t , char *s)
{
//move pointer t to end of the string it points.
while(*t != '\0'){
t++;
}
while( *s != '\0' ){
*t = *s;
t++;
s++;
}
}
If i have char* str; how do I write a function that accepts str and can make changes to str so that, the changes persist after the function returns?
what I have is:
char *str = (char *) malloc(10);
sprintf(str, "%s", "123456789");
//str points to 1
move_ptr(&str);
//str points to 2
void move_ptr(char** str)
{
*str++;
}
is there a better way to do that?
Just access the data through the pointer, in the function:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
void change_string(char *str)
{
size_t i;
/* As an example, make it all upper case. */
for(i = 0; str[i]; ++i)
str[i] = toupper(str[i]);
}
int main(void)
{
char buffer[32];
char *str = buffer;
strcpy(str, "test string");
change_string(str);
printf("it's now %s\n", str);
return EXIT_SUCCESS;
}
Come to think of it, you'll notice that the standard strcpy() function is exactly of the category you describe. It's a very common operation in C.
UPDATED: The question has been significantly rewritten, now it seems to be more about changing the pointer itself, rather than the data. Perhaps this was the meaning all along, but I didn't understand.
The solution in the question is fine, but personally I find it more convenient to work with return values, if possible:
char * change_pointer(char *str)
{
return str + 1;
}
int main(void)
{
char *str = "test string";
printf("now '%s'\n", str);
str = change_pointer(str);
printf("now '%s'\n", str);
return EXIT_SUCCESS;
}
The pointer(s) could of course also be const-declared, and should be if no changes to the buffered text are needed.
Question changed
If your pointer points to readonly data, you can't change what it points to.
When one writes
char *data = "forty two";
that "forty two" is readonly data; and you can't change what the pointer data points to whether directly or through a function call.
To get a 'string' initialized from a literal constant, instead of assigning a pointer to the literal constant, copy the characters to an array
char data[] = "forty two";
Now data is an array of 10 characters (9 for the letters and space + 1 for the NUL terminator) which you can change at will.
Your example may be over simplified, but just in case... Be careful of doing things like this because you're going to leak memory. After your function call, you no longer have a pointer to (part of) the original memory you allocated.
As mentioned by unwind, returning the new pointer may be a better choice. While it achieves the same goal, it makes it more obvious that you need to keep the original pointer around for the purposes of releasing the memory. The counter argument being that it gives the impression that you can free the original pointer once you have the return value, which you can't do because they both point at (different locations) in the same memory block.