I was trying to understand pointers better, especially with string literals. I wanted to print a letter's bits in a string literal.
My main simply contains:
char *a = "A";
showBits(a);
and the function looks like that:
void showBits(char *character) {
int size = sizeof(char);
const unsigned int maxPow = 1<<(size*8-1); // 128
int j;
int temp = -1;
for(j=0;j<8;j++) {
temp = (*character)&maxPow;
printf("2%u", !!((*character)&maxPow));
*character = *character << 1;
}
}
Obviously the code does not work. I could make the code work with a[] = "A" but that was not my intention, I wanted to work with pointers to understand them better. I wonder, if there is a way to make this work?
I could imagine, that you can extract the bits, when you simply right shift maxPow and do a logial comparison with &, but is there a way to do it/work with the pointer?
Also I was thinking of passing the address to the function by showBits(&a), but can you then go through the addresses bit by bit?
The assignment to character tries to modify a string literal which is not possible. When you change the code to char a[] = "A", a stack-allocated array is created which is initalized with 'A''\0' and can be modified.
As a rule, you should always use a char const* when using string literals. This would have prevented the issue completely. I think the compiler should have generated a warning.
I think you could just pass the char by value and then everything will work.
void showBits(char character) {
const unsigned char maxPow = 128;
int j;
for(j=0;j<8;j++) {
printf("%u", 0 != (character & maxPow) );
character <<= 1;
}
}
int main()
{
char const* a = "\127";
showBits(*a);
}
I also simplified the function a bit because sizeof(char)is always 1 and removed some redundant code.
This is probably the most frequently asked question here (at least under C/C++).
Using "A", you have an array of characters "A\0" allocated in a read-only memory segment within your program (typically in the RO data-section).
Every time a function declaring char* a = "A" is called, a local variable is allocated on the stack and initialized to point to the address of "A\0" in memory.
Since this variable points to a read-only memory segment, any attempt to change the pointed data is likely to yield a memory access violation during runtime.
Every time a function declaring char a[] = "A" is called, a local array is allocated on the stack and initialized with the contents of "A\0" in memory.
Since this array resides in a writable memory segment, the program can safely change its contents during runtime (as long as it doesn't exceed its boundaries).
Instead of trying to do *character = *character << 1 and bitops with maxPow, just print (*character)&(1<<j).
int size_in_bits = sizeof(char)*8;
for(j=0;j<8;j++) {
printf("2%u", !!((*character)&(1<<(size_in_bits - 1 - j));
}
Try something like this:
void showBits(char *character) {
char result[10];
int mask = 0x80;
for (int j = 7; j >= 0; j -= 1) {
result[7-j] = (mask & *character) ? '1' : '0';
mask >>= 1;
}
result[8] = '\0';
printf("%s\n", result);
}
I would divide the functionality into two functions:
void showBitsOne(unsigned char c, int bits_left)
{
int bit = 0;
if ( bits_left <= 0 )
{
return;
}
// Print the bit.
bit = ((c & (1 << (bits_left-1))) == (1 << (bits_left-1)));
printf("%d", bit);
// Recurse.
showBitsOne(c, bits_left - 1);
}
void showBits(const char *character) {
while ( *character != '\0' )
{
showBitsOne(*character, CHAR_BIT);
printf(" "); // Just add a space between characters.
++character;
}
printf("\n");
}
With the following main function
int main()
{
showBits("abcd");
return 0;
}
I get the output:
01100001 01100010 01100011 01100100
Related
void to_string(int x)
{
int value, i = 0;
char numericalChar[] = "0123456789";
char *string;
do
{
value = x % 10;
string[i++] = numericalChar[value];
x /= 10;
} while(x >= 0);
printf("%s\n", string);
}
I am trying to write a function that turns an integer into a string. I don't think there is nothing with my logic but I am getting a segfault and my printf() is not printing anything out. I probably missing something obvious. I have been sitting in front of the computer for an hour and still, I can't figure it out. Thanks in advance.
I guess you know that there are in fact standard function for this (e.g. sprintf - see example below) but just want to write it yourself, right...
In that case:
First of all you need to assign memory to hold the string. Using a char pointer is not enough. You get a seg fault because of that. A uninitialized pointer just points somewhere into memory where you are (most likely) not allowed to write. So when do... it seg faults. In this case just use a short fixed size char array instead.
Second it is much easier just to add each digit to the char '0' to get the correct digit. No need for an array as look up table.
Something like:
void to_string(int x)
{
char string[32] = "0";
if (x > 0)
{
char temp[32] = {0};
int i = 31;
// Build a temp string from from the end (right to left)
while(x > 0)
{
temp[--i] = '0' + (x % 10);
x /= 10;
}
// Copy the temp string to the target variable
strcpy(string, &temp[i]);
}
printf("%s\n", string);
}
Notice that this code only handles integers greater than or equal to zero. I'll leave negative integers as an exercise.
If you want to use e.g. sprintf it's as easy as:
int n = 42;
char string[32];
sprintf(string, "%d", n);
printf("%s\n", string);
So as people already commented on your question, you have not allocated space so:
char *string;
should be
char *string = malloc ( sizeof (char) * numberOfDigits);
and there is another seg fault that I could not figure out, while I fix it I will give you this:
itoa solutions
void to_string(int x) {
string s = "";
while(x){
s += (x % 10) + 48;
x /= 10;
}
printf("%s\n", s);
}
"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.
code 1:
.
.
int main()
{
char ch1[3];
ch1[0]=ch1[1] = NULL;
ch1[2]=0x01;
ch1[2] = ch1[2]<<2;
printf("%u", ch1[2]);
system("PAUSE");
return 0;
}
.
.
the output of code:1 is 4 (as expected).
code 2:
.
.
int main()
{
char ch1[3];
ch1[0]=ch1[1] = NULL;
ch1[2]=0x01;
*ch1 = *ch1<<2;
printf("%u", ch1[2]);
system("PAUSE");
return 0;
}
.
.
but the output of code:2 is 1 as not expected! in line 6 of code:2, the modification done was changing ch1[2] = ch1[2]<<2; to *ch1 = *ch1<<2;. I have tried treating the char array as one numerical value and have done the << operation; I believe that my method is incorrect. is there any correct method to treat an array as a single numerical value to do basic mathematical operations?
Update 1:
I have changed my code to the following:
int main()
{
char ch1[3];
ch1[0]=ch1[1] = NULL;
ch1[2]=0x01;
*(ch1+2) = *(ch1+2)<<9;
printf("%u", ch1[1]);
system("PAUSE");
return 0;
}
now I get the output:0. shouldn't I be getting the output 2 (i.e. 2^(9-8))? still, how to treat an array as a single numerical value?
right; but my actual question is if its possible to treat an array as a single value or not; that is by considering ch1[0], ch1[1], ch1[2] as a single block of memory of 24 bits.
The type of the pointer is important ch1 is similar to a pointer to char- char*. when you do *ch1 you are refering to the char that ch1 is pointing at. if you want to treat the entire array as a number you need to cast it into an integer, which is also problematic because your array has 3 bytes, and an integer has 4, so the top byte of x in the example below is pointing at, is actually undefined
int main()
{
char ch1[3];
ch1[0]=ch1[1] = 0;
ch1[2]=0x01;
int *x = (int*)ch1;
*x <<= 2;
printf("%u", ch1[2]);
system("PAUSE");
return 0;
}
The code I have is quite simple in one method I have this:
// This line has an Intellisense Error: Initialization with {...} expected for aggregate object
char str[] = GetBuffer(); // x 64 will give us 512 (sector sized buffer) ;
The GetBuffer metod is this:
char * GetBuffer(void)
{
int idx = 0;
int offset = 0;
char *buffer[512];
for(idx =0; idx < 64; idx ++)
{
// This line has an Itellisense Error: "Expected Expression"
buffer[offset + idx] = {"E","R","A","S","E","D"," ", " "};
offset += 8;
}
return *buffer;
}
Any ideas what's wrong with this?
All I am trying to do - is populate a buffer with 512 bytes which contain the following string repeated: "ERASED " This is ANSI C (not C++) and it has been so long since I coded in ANSI C - please help and be kind!
Using Visual Studio 2012
EDIT 1
Ok lots of things have been fixed thanks to you guys - but no full answer yet.
The str buffer holds 528 characters and not 512 and contains a lot of ERASED as expected but ends with
ýýýý««««««««îþîþ
Any ideas with this? And Oh boy I have a great deal of pure C reading to do - I have forgotten way too much!
You can't initialize an array with the return value from a function.
You could use a pointer instead of an array:
char *str = GetBuffer();
Or you could use strcpy() or a relative — but there are buffer overflow risks:
char str[512];
strcpy(str, GetBuffer());
Your GetBuffer() function also has a lot of problems.
char *GetBuffer(void)
{
int idx = 0;
int offset = 0;
char *buffer[512];
This should probably be char buffer[512];, but...
for(idx =0; idx < 64; idx ++)
{
// This line has an Itellisense Error: "Expected Expression"
buffer[offset + idx] = {"E","R","A","S","E","D"," ", " "};
You can't set arrays like this. And you needed double quotes because of the char *buffer[512] problem.
offset += 8;
}
return *buffer;
}
And you should not return a local variable — it is destroyed when the function returns so it can't be used afterwards.
You might write:
char *GetBuffer(void)
{
char *buffer = malloc(257);
if (buffer != 0)
{
int idx;
for (idx = 0; idx < 256; idx += 8)
strcpy(buffer+idx, "ERASED ");
}
return buffer;
}
There's a small layer of obfuscation going on with the hard-coded lengths and limits; they're correct, but the interconnections between the sizes are not obvious — and ideally, they should be:
strlen("ERASED ") == 8
256 = 32 * strlen("ERASED ")
257 = 32 * strlen("ERASED ") + 1 (the one is for the terminal null)
And then the calling code might be:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *str = GetBuffer();
if (str != 0)
{
printf("<<%s>>\n", str);
free(str);
}
return(0);
}
there is problem with your buffer creation. you'd malloc such that it's not reclaimed by the function invoke routine. Second, you can't do assignment like the line you encountered a Itellisense error.
You can use this:
#include "stdlib.h"
char * GetBuffer(void)
{
int i = 0, idx = 0;
const char * cstr_init = "ERASED ";
char *buffer = (char*)malloc(512);
for (idx = 0; idx < 512; idx+=8) {
for (i = 0; i < 8; i++) {
buffer[idx+i] = cstr_init[i];
}
}
return buffer;
}
There are several things wrong here.
In C, a character array can be initialized with an initializer list or a string literal. You cannot use the return value from a function to initialize the array. So
char str[] = GetBuffer();
will not work.
Also, char* buffer [512] is an array of 512 pointers to char, i.e., an array of 512 strings. buffer [offset + idx] would be one pointer to char. It can hold only one string, but you are trying to assign eight strings to it: "E", "R", etc. If you mean those to be chars and not strings, use single quotes: 'E', etc. However, even that won't work unless you allocate memory to the pointer so that it can hold the string.
As written, the array of pointers is allocated on the stack, so it goes out of scope when the function terminates. return *buffer would return the first string in the array of strings, but that's a local variable, so you're returning the dereferenced value of a pointer that is no longer in scope.
I think a simpler way to accomplish your goal is this:
char str [512] = {'\0'};
for (int i = 0; i < 511; i += 7)
strcat (str + i, "ERASED ");
It's not very general, but it does what you want.
Edited to reflect Jonathan Leffler's comment that strcat (str, "ERASED "), which is what I originally had, is inefficient.
I'm starting to learn C by reading K&R and going through some of the exercises. After some struggling, I was finally able to complete exercise 1-19 with the code below:
/* reverse: reverse the character string s */
void reverse(char s[], int slen)
{
char tmp[slen];
int i, j;
i = 0;
j = slen - 2; /* skip '\0' and \n */
tmp[i] = s[j];
while (i <= slen) {
++i;
--j;
tmp[i] = s[j];
}
/* code from copy function p 29 */
i = 0;
while ((s[i] = tmp[i]) != '\0')
++i;
}
My question is regarding that last bit of code where the tmp char array is copied to s. Why doesn't a simple s = tmp; work instead? Why does one have to iterate through the array copying index by index?
Maybe I'm just old and grumpy, but the other answers I've seen seem to miss the point completely.
C does not do array assignments, period. You cannot assign one array to another array by a simple assignment, unlike some other languages (PL/1, for instance; Pascal and many of its descendants too - Ada, Modula, Oberon, etc.). Nor does C really have a string type. It only has arrays of characters, and you can't copy arrays of characters (any more than you can copy arrays of any other type) without using a loop or a function call. [String literals don't really count as a string type.]
The only time arrays are copied is when the array is embedded in a structure and you do a structure assignment.
In my copy of K&R 2nd Edition, exercise 1-19 asks for a function reverse(s); in my copy of K&R 1st Edition, it was exercise 1-17 instead of 1-19, but the same question was asked.
Since pointers have not been covered at this stage, the solution should use indexes instead of pointers. I believe that leads to:
#include <string.h>
void reverse(char s[])
{
int i = 0;
int j = strlen(s) - 1;
while (i < j)
{
char c = s[i];
s[i++] = s[j];
s[j--] = c;
}
}
#ifdef TEST
#include <stdio.h>
int main(void)
{
char buffer[256];
while (fgets(buffer, sizeof(buffer), stdin) != 0)
{
int len = strlen(buffer);
if (len == 0)
break;
buffer[len-1] = '\0'; /* Zap newline */
printf("In: <<%s>>\n", buffer);
reverse(buffer);
printf("Out: <<%s>>\n", buffer);
}
return(0);
}
#endif /* TEST */
Compile this with -DTEST to include the test program and without to have just the function reverse() defined.
With the function signature given in the question, you avoid calling strlen() twice per line of input. Note the use of fgets() — even in test programs, it is a bad idea to use gets(). The downside of fgets() compared to gets() is that fgets() does not remove the trailing newline where gets() does. The upsides of fgets() are that you don't get array overflows and you can tell whether the program found a newline or whether it ran out of space (or data) before encountering a newline.
Your tmp array was declared on stack and so when your method completes, the memory used to hold the values will be freed because of scoping.
s = tmp means that s should point to the same memory location as tmp. This means that when tmp is freed, s will still be pointing to a now possible invalid, freed memory location.
This type of error is referred to as a dangling pointer.
Edit: This isn't a dangling modifier as pointed out in the comments of this answer. The issue is that saying s = tmp only changes what the parameter points to, not what the actual array that was passed.
Also, you could perform your reverse with a single pass and without allocating a whole array in memory by just swapping the values in place one by one:
void reverse(char s[], int slen) {
int i = 0; // First char
int j = slen - 2; // Last char minus \n\0
char tmp = 0; // Temp for the value being swapped
// Iterate over the array from the start until the two indexes collide.
while(i < j) {
tmp = s[i]; // Save the eariler char
s[i] = s[j]; // Replace it with the later char
s[j] = tmp; // Place the earlier char in the later char's spot
i++; // Move forwards with the early char
j--; // Move backwards with the later char
}
}
Because both s and tmp are memory addressees. If you s = tmp, both pointers would point to the same array.
Suppose that we have
char s[] ="ab";
/*
* Only for explanatory purposes.
*
*/
void foo(char s[]){
char tmp [] = "cd";
s= tmp;
}
foo(s);
after s= tmp you would have
s[0] : 'c'
s[1] : 'd'
s[2] : '\0'
Even though both arrays have the same data, a change in tmp, will affect both of them, because both arrays are actually the same. They both contain data that´s in the same memory address. So by changing any position of the tmp array, or destroying the tmp array, s would be affected in the same way.
By looping over the array, what you are doing is moving a piece of data from one memory address to another.
In my copy of K & R, pointers are explained in chapter 4. A quick glance through the first pages may be of help.
To round out the discussion here are two other possible ways to reverse as string:
void reverse(char string1[], char string2[])
{
int i = 0, len = 0;
while(string2[len] != '\0') // get the length of the string
len++;
while(len > 0)
{
string1[i] = string2[len-1]; // copy the elements in reverse
i++;
len--;
}
string1[i] = '\0'; // terminate the copied string
}
Or recursively:
void reverse (const char *const sPtr)
{
//if end of string
if (sPtr[0] == '\0')
{
return;
}
else //not end of the string...
{
reverse(&sPtr[1]); //recursive step
putchar(sPtr[0]); //display character
}
}
because tmp is a pointer, and you need to get a copy, not a "link".
In case of s=tmp, the value of tmp which is the also the beginning address of the array, would get copied to s.
That way both s and tmp will point to the same address in memory, which I think is not the purpose.
cheers
Try experimenting and see what happens when you do things like this:
void modifyArrayValues(char x[], int len)
{
for (int i = 0; i < len; ++i)
x[i] = i;
}
void attemptModifyArray(char x[], int len)
{
char y[10];
for (int i = 0; i < len; ++i)
y[i] = i;
x = y;
}
int main()
{
int i = 0;
char x[10];
for (i = 0; i < 10; ++i)
x[i] = 0;
attemptModifyArray(x, 10);
for (i=0; i < 10; ++i)
printf("%d\n", x[i]); // x is still all 0's
modifyArrayValues(x, 10);
for (i=0; i < 10; ++i)
printf("%d\n", x[i]); // now x has 0-9 in it
}
What happens when you modify the array directly in attemptModifyArray, you are just overwriting a local copy of the address of the array x. When you return, the original address is still in main's copy of x.
When you modify the values in the array in modifyArrayValues, you are modifying the actual array itself which has its address stored in modifyArrayValues local copy of x. When you return, x is still holding on to the same array, but you have modified the values in that array.
There's an interesting sub-thread in this thread about arrays and pointers
I found this link on wikipedia with a peculiar code snippet showing just how 'plasticine' C can be!
/* x designates an array */
x[i] = 1;
*(x + i) = 1;
*(i + x) = 1;
i[x] = 1; /* strange, but correct: i[x] is equivalent to *(i + x) */
Of course what's even more confusing in C is that I can do this:
unsigned int someval = 0xDEADD00D;
char *p = (char *)&someval;
p[2] = (char)0xF0;
So the interchangibility of pointers and arrays seems so deep-set in the C language as to be almost intentional.
What does everyone else think?
---Original Post---
s and tmp are both pointers so doing s = tmp will simply make s point at the address where tmp lives in memory.
Another problem with what you outlined is that tmp is a local variable so will become 'undefined' when it goes out of scope i.e when the function returns.
Make sure you thoroughly grasp these three concepts and you won't go far wrong
Scope
The difference between the stack and the heap
Pointers
Hope that helps and keep going!
A very straight forward answer would be -
both s and tmp are pointers to a memory location and not the arrays themselves.
In other words, s and tmp are memory addresses where the array values are stored but not the values themselves.
And one of the common ways to access these array values are by using indices like s[0] or tmp[0].
Now, if you will try to simply copy, s = tmp, the memory address of tmp array will be copied over to s. This means that, the original s array will be lost and even s memory pointer will now point to tmp array.
You will understand these concepts well with due time so keep going through the book.
I hope this elementary explanation helps.