I'm using scanf to read a string and put it into a char*.
scanf("%s", &str);
printf("%c",str);
It works fine but I don't know how to access a specific character in that string as I would with a char[]. I have been trying to increment the address:
str += 1;
I have been messing around a bit but all I get is the first character or segfaults or bus errors. Is it possible to work with that string without copying into a char[]?
1)
It works fine but I don't know how to access a specific character in that string as I would with a char[]
Just dereference the pointer-array with [] and access the character at position "i"
str[i]
2)
I have been messing around a bit but all I get is the first character or segfaults or bus errors
Yes - the arrayname itself is a pointer to the first character of the string
If str is declared as char * then this statement
scanf("%s", &str);
is incorrect. There has to be
scanf("%s", str);
And the next statement
printf("%c",str);
is also incorrect. There has to be
printf("%c", *str);
If you want to output some other character in the character array using pointer char * then you can write either
printf( "%c", *( str + n ) );
or
printf( "%c", str[n] );
or even as
printf( "%c", n[str] );
where n some integer value that less then strlen( str )
Take into account that str shall point to some allocated memory. Otherwise the program will have undefined behaviour.
Related
i got a string and a scanf that reads from input until it finds a *, which is the character i picked for the end of the text. After the * all the remaining cells get filled with random characters.
I know that a string after the \0 character if not filled completly until the last cell will fill all the remaining empty ones with \0, why is this not the case and how can i make it so that after the last letter given in input all the remaining cells are the same value?
char string1 [100];
scanf("%[^*]s", string1);
for (int i = 0; i < 100; ++i) {
printf("\n %d=%d",i,string1[i]);
}
if i try to input something like hello*, here's the output:
0=104
1=101
2=108
3=108
4=111
5=0
6=0
7=0
8=92
9=0
10=68
You have an uninitialized array:
char string1 [100];
that has indeterminate values. You could initialize the array like
char string1 [100] = { 0 };
or
char string1 [100] = "";
In this call
scanf("%[^*]s", string1);
you need to remove the trailing character s, because %[] and %s are distinct format specifiers. There is no %[]s format specifier. It should look like this:
scanf("%[^*]", string1);
The array contains a string terminated by the zero character '\0'.
So to output the string you should write for example
for ( int i = 0; string1[i] != '\0'; ++i) {
printf( "%c", string1[i] ); // or putchar( string1[i] );
putchar( '\n' );
or like
for ( int i = 0; string1[i] != '\0'; ++i) {
printf("\n %d=%c",i,string1[i]);
putchar( '\n' );
or just
puts( string1 );
As for your statement
printf("\n %d=%d",i,string1[i]);
then it outputs each character (including non-initialized characters) as integers due to using the conversion specifier d instead of c. That is the function outputs internal ASCII representations of characters.
I know that a string after the \0 character if not filled completly
until the last cell will fill all the remaining empty ones with \0
No, that's not true.
It couldn't be true: there is no length to a string. No where neither the compiler nor any function can even know what is the size of the string. Only you do. So, no, string don't autofill with '\0'
Keep in minds that there aren't any string types in C. Just pointer to chars (sometimes those pointers are constant pointers to an array, but still, they are just pointers. We know where they start, but there is no way (other than deciding it and being consistent while coding) to know where they stop.
Sure, most of the time, there is an obvious answer, that make obvious for any reader of the code what is the size of the allocated memory.
For example, when you code
char string1[20];
sprintf(string1, "hello");
it is quite obvious for a reader of that code that the allocated memory is 20 bytes. So you may think that the compiler should know, when sprinting in it of sscaning to it, that it should fill the unused part of the 20 bytes with 0. But, first of all, the compiler is not there anymore when you will sscanf or sprintf. That occurs at runtime, and compiler is at compilation time. At run time, there is not trace of that 20.
Plus, it can be more complicated than that
void fillString(char *p){
sprintf(p, "hello");
}
int main(){
char string1[20];
string1[0]='O';
string1[1]='t';
fillString(&(string1[2]));
}
How in this case does sprintf is supposed to know that it must fill 18 bytes with the string then '\0'?
And that is for normal usage. I haven't started yet with convoluted but legal usages. Such as using char buffer[1000]; as an array of 50 length-20 strings (buffer, buffer+20, buffer+40, ...) or things like
union {
char str[40];
struct {
char substr1[20];
char substr2[20];
} s;
}
So, no, strings are not filled up with '\0'. That is not the case. It is not the habit in C to have implicit thing happening under the hood. And that could not be the case, even if we wanted to.
Your "star-terminated string" behaves exactly as a "null-terminated string" does. Sometimes the rest of the allocated memory is full of 0, sometimes it is not. The scanf won't touch anything else that what is strictly needed. The rest of the allocated memory remains untouched. If that memory happened to be full of '\0' before the call to scanf, then it remains so. Otherwise not. Which leads me to my last remark: you seem to believe that it is scanf that fills the memory with non-null chars. It is not. Those chars were already there before. If you had the feeling that some other methods fill the rest of memory with '\0', that was just an impression (a natural one, since most of the time, newly allocated memory are 0. Not because a rule says so. But because that is the most frequent byte to be found in random area of memory. That is why uninitialized variables bugs are so painful: they occur only from times to times, because very often uninitialized variables are 0, just by chance, but still they are)
The easiest way to create a zeroed array is to use calloc.
Try replacing
char string1 [100];
with
char *string1=calloc(1,100);
When I press a key(integer) on my keyboard. It does something like:
gchar *keypressed;
keypressed=gdk_keyval_name (event->keyval);
printf("The KeyEvent is: %s\n", keypressed); // Till here it is fine
I get segmentation fault when I do this:
char ch;
sprintf(ch, "%s\n", keypressed);
printf("The NewKeyEvent is: %s\n",ch);
I need to convert it as I am going to use the value in a switch case. Without converting it is not possible.
gchar is a typedef alias of char, so the problem is not with the type conversion. You need to allocate some space for the sprintf buffer.
Currently, you are passing a single uninitialized char to where a pointer should be. You should get a warning from the compiler, in addition to a segfault caused by undefined behavior.
To fix this, make an array of chars and pass it to sprintf instead:
char ch[10];
sprintf(ch, "%8s\n", keypressed);
printf("The NewKeyEvent is: %s\n", c);
Note the limit of 8 in the sprintf. This is because ch is of size 10, and we need two extra spots for '\n' and '\0'.
If you want only a single character from the keypressed string there are two ways:
Use array indexing, this way you can access any character in the string:
char ch = keypressed[x]; // Where `x` is the character number you want
Remember that array indexing starts from zero, so the first character in the string is number 0.
If you want the first character, you can also use the dereference operator
char ch = *keypressed;
This equivalent to
char ch = keypressed[0];
I'm trying to tokenize a phone number and split it into two arrays. It starts out in a string in the form of "(515) 555-5555". I'm looking to tokenize the area code, the first 3 digits, and the last 4 digits. The area code I would store in one array, and the other 7 digits in another one. Both arrays are to hold just the numbers themselves.
My code seems to work... sort of. The issue is when I print the two storage arrays, I find some quirks;
My array aCode; it stores the first 3 digits as I ask it to, but then it also prints some garbage values notched at the end. I walked through it in the debugger, and the array only stores what I'm asking it to store- the 515. So how come it's printing those garbage values? What gives?
My array aNum; I can append the tokens I need to the end of it, the only problem is I end up with an extra space at the front (which makes sense; I'm adding on to an empty array, ie adding on to empty space). I modify the code to only hold 7 variables just to mess around, I step into the debugger, and it tells me that the array holds and empty space and 6 of the digits I need- there's no room for the last one. Yet when I print it, the space AND all 7 digits are printed. How does that happen?
And how could I set up my strtok function so that it first copies the 3 digits before the "-", then appends to that the last 4 I need? All examples of tokenization I've seen utilize a while loop, which would mean I'd have to choose either strcat or strcpy to complete my task. I can set up an "if" statement to check for the size of the current token each time, but that seems too crude to me and I feel like there's a simpler method to this. Thanks all!
int main() {
char phoneNum[]= "(515) 555-5555";
char aCode[3];
char aNum[7];
char *numPtr;
numPtr = strtok(phoneNum, " ");
strncpy(aCode, &numPtr[1], 3);
printf("%s\n", aCode);
numPtr = strtok(&phoneNum[6], "-");
while (numPtr != NULL) {
strcat(aNum, numPtr);
numPtr = strtok(NULL, "-");
}
printf("%s", aNum);
}
I can primarily see two errors,
Being an array of 3 chars, aCode is not null-terminated here. Using it as an argument to %s format specifier in printf() invokes undefined behaviour. Same thing in a differrent way for aNum, too.
strcat() expects a null-terminated array for both the arguments. aNum is not null-terminated, when used for the first time, will result in UB, too. Always initialize your local variables.
Also, see other answers for a complete bug-free code.
The biggest problem in your code is undefined behavior: since you are reading a three-character constant into a three-character array, you have left no space for null terminator.
Since you are tokenizing a value in a very specific format of fixed length, you could get away with a very concise implementation that employs sscanf:
char *phoneNum = "(515) 555-5555";
char aCode[3+1];
char aNum[7+1];
sscanf(phoneNum, "(%3[0-9]) %3[0-9]-%4[0-9]", aCode, aNum, &aNum[3]);
printf("%s %s", aCode, aNum);
This solution passes the format (###) ###-#### directly to sscanf, and tells the function where each value needs to be placed. The only "trick" used above is passing &aNum[3] for the last argument, instructing sscanf to place data for the third segment into the same storage as the second segment, but starting at position 3.
Demo.
Your code has multiple issues
You allocate the wrong size for aCode, you should add 1 for the nul terminator byte and initialize the whole array to '\0' to ensure end of lines.
char aCode[4] = {'\0'};
You don't check if strtok() returns NULL.
numPtr = strtok(phoneNum, " ");
strncpy(aCode, &numPtr[1], 3);
Point 1, applies to aNum in strcat(aNum, numPtr) which will also fail because aNum is not yet initialized at the first call.
Subsequent calls to strtok() must have NULL as the first parameter, hence
numPtr = strtok(&phoneNum[6], "-");
is wrong, it should be
numPtr = strtok(NULL, "-");
Other answers have already mentioned the major issue, which is insufficient space in aCode and aNum for the terminating NUL character. The sscanf answer is also the cleanest for solving the problem, but given the restriction of using strtok, here's one possible solution to consider:
char phone_number[]= "(515) 555-1234";
char area[3+1] = "";
char digits[7+1] = "";
const char *separators = " (-)";
char *p = strtok(phone_number, separators);
if (p) {
int len = 0;
(void) snprintf(area, sizeof(area), "%s", p);
while (len < sizeof(digits) && (p = strtok(NULL, separators))) {
len += snprintf(digits + len, sizeof(digits) - len, "%s", p);
}
}
(void) printf("(%s) %s\n", area, digits);
I am studying pointers right now. So, arrays are simultaneously studied with that. It says that address of first of element of array arr is &arr[0] which can also be written as arr.
But as i know that string is an array of characters so if have a string:
char string[] = "ilovejapan";
and then print it using printf
printf("%s", string);
shouldn't it be just printing the first address? Really confused Now.
Question updated: Now in the example below *W points to word that means it pointers to the first address of the string word right? How does this access complete string word?
int getword(char *word, int lim)
{
int c, getch(void);
void ungetch(int);
char *W = word;
while (isspace(c = getch()))
;
if (c != EOF)
*W++ = c;
if (lisalpha(c)) {
*W = '\0';
return c;
}
for ( ; --lim > 0; W++)
if ( lisalnum(*W = getch())) {
ungetch ( *W) ;
break;
}
*W = '\0';
return word[O];
}
The conversion specifier %s says, "Give me the address of a character. I will print that character, and then look at the next higher address and print that character, and so forth, until the character at the address I'm looking at is zero". So string is indeed the address of a character, but printf knows what to do with it.
char string[0] = "ilovejapan"; isn't a valid declaration. Maybe you meant to leave the 0 out?
Anyway, the %s format specifier is intended to match up with a pointer to a string, which in your case is just fine. It prints characters from that address up until the terminating null character.
When you pass string in printf("%s", string);, you are telling printf you want to print a string and you are telling the function the address of the first character in the string. Using its address, printf can figure out what character is stored at that address, and increments the address of the first character to get the address of the second character, and prints that character, and so on. It stops printing when it finds a character (not that character's address, but the actual character itself) whose value is '\0' (the "zero" character, or the character represented by the number 0). If that makes any sense.
I'm dusting off of my C skills for an upcoming class and I came across this weird output with printf after building a string using getchar. Specifically, any string I try to output gets the same sequence of characters appended to each letter. foo becomes "f?8#{?o?8#{?o?8#{?" compiling with cc, and f¿:¿o¿:¿0¿:¿ with Apple LLVM 5.0 (Xcode). Here is the sample code that illustrates the issue:
char * input_buffer = malloc( sizeof( char ) );
char c;
while ( ( c = getchar() ) != '\n' ) {
strcat(input_buffer, &c);
}
// problem output
printf( "\n%s\n", input_buffer );
// foo -> f¿:¿o¿:¿0¿:¿
// weird side effect is the 4 is required to get a proper len
printf("\ncharacters: %lu\n", strlen( input_buffer ) / 4 );
I've searched everywhere but I'm not seeing this anywhere else, but then this seems like a bit of an edge case. Is this is some kind of an encoding issue that I am not taking into account?
You cannot call strcat(input_buffer, &c);.
Each of the arguments passed to strcat must be a valid null-terminated string of characters.
The chances of the next byte after &c being 0 are pretty slim.
The chances of the first byte pointed by input_buffer being 0 aren't very high either.
In other words, strcat reads "junk" until it encounters a 0 character, in both arguments.
Change:
while ( ( c = getchar() ) != '\n' ) {
strcat(input_buffer, &c);
}
To:
for (int i=0; 1; i++)
{
c = getchar();
if (c == '\r' || c == '\n')
{
input_buffer[i] = 0;
break;
}
input_buffer[i] = c;
}
You are allocating space to input_buffer for only one char.
strcat(input_buffer, &c); is wrong. You are concatenating character (it is not null terminated) with a string.
getchar returns int type but you declared c is of type char.
char * input_buffer = malloc( sizeof( char ) );
sizeof (char) is 1 by definition. This allocates space for a single character, and makes input_buffer point to it.
You're also not checking whether the allocation succeeded. malloc returns a null pointer on failure; you should always check for that.
And the allocated char object that input_buffer points to contains garbage.
char c;
while ( ( c = getchar() ) != '\n' ) {
strcat(input_buffer, &c);
}
getchar() returns an int, not a char. You can assign the result to a char object, but by doing so you lose the ability to detect and end-of-file or error condition. getchar() returns EOF when there are no more characters to be read; you should always check for that, and doing so requires storing the result in an int. (EOF is an integer value that's unequal to any valid character.)
strcat(input_buffer, &c);
input_buffer points to a single uninitialized char. You can treat it as an array consisting of a single char element. The first argument to strcat must already contain a valid null-terminated string, and it must have enough space to hold that string plus whatever you're appending to it.
c is a single char object, containing whatever character you just read with getchar(). The second argument tostrcatis achar*, so you've got the right type -- but thatchar*` must point to a valid null-terminated string.
strcat will first scan the array pointed to by input_buffer to find the terminating '\0' character so it knows where to start appending -- and it will probably scan into memory that's not part of any object you've declared or allocated, possibly crashing your program. If that doesn't blow up, it will then copy characters starting at c, and going past it into memory that you don't own. You have multiple forms of undefined behavior.
You don't need to use strcat to append a single character to a string; you can just assign it.
Here's a simple example:
char input_buffer[100];
int i = 0; /* index into input_buffer */
int c;
while ((c = getchar()) != '\n' && c != EOF) {
input_buffer[i] = c;
i ++;
}
input_buffer[i] = '\0'; /* ensure that it's properly null-terminated */
I allocated a fixed-size buffer rather than using malloc, just for simplicity.
Also for simplicity, I've omitted any check that the input doesn't go past the end of the input buffer. If it does, the program may crash if you're lucky; if you're not lucky, it may just appear to work while clobbering memory that doesn't belong to you. It will work ok if the input line isn't too long. In any real-world program, you'll want to check for this.
BTW, what's being done here is more easily done using fgets() -- but it's good to learn how things work on a slightly lower level.